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

acm.io.IOConsole 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!
/*
 * @(#)IOConsole.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
//
// -- V2.0 --
// Bug fix 18-Feb-07 (ESR, JTFBug 2007-003, reported by Dale Skrien)
//   1. Fixed bug in ConsoleModel.clear.
//
// Bug fix 08-May-07 (ESR, JTFBug 2007-008)
//   1. Completely rewrote PrintConsole code which no longer worked in JDK 1.6.
//
// Code cleanup 21-May-08 (ESR)
//   1. Reimplemented menu bar code to correspond to overall redesign of
//      the ProgramMenuBar class.

package acm.io;

import acm.program.*;
import acm.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;

/* Class: IOConsole */
/**
 * The IOConsole class makes it easier to interact with
 * the user using text-based input and output in the style of a
 * traditional console.  Given a IOConsole object, you
 * can write output to that console using the
 * print and
 * println
 * methods, just as you would for the standard output stream.
 * To request input from the user, the most common methods are
 *
 * 
 *
 * 

 

A IOConsole object is a lightweight component and must be * added to an installed Frame or JFrame before it becomes * visible on the screen. The usual strategy for including a console in a frame is * to use the ConsoleProgram * mechanism in the acm.program package. * * The operation of the IOConsole class is illustrated by * the following test method, which generates the session shown on * the right. The user input appears in blue, * just as it does in the console window. * *

 

*
Console example

 *      public void test(IOConsole console) {
 *         console.println("IOConsole class test");
 *         int n = console.readInt("Enter an integer: ");
 *         console.println("That integer was " + n);
 *         double d = console.readDouble("Enter a real number: ");
 *         console.println("That number was " + d);
 *         boolean b = console.readBoolean("Enter a boolean value: ");
 *         console.println("That value was " + b);
 *         String line = console.readLine("Enter a line: ");
 *         console.println("That line was \"" + line + "\"");
 *      }
 * 
* Console Test *
*/ public class IOConsole extends Container implements IOModel { /* Constant: SYSTEM_CONSOLE */ /** * This constant is an object that offers the functionality of the * IOConsole class, but which does so using the standard * I/O streams System.in and System.out. */ public static final IOConsole SYSTEM_CONSOLE = new SystemConsole(); /* Constructor: IOConsole() */ /** * Creates a new IOConsole object. * * Example: IOConsole console = new IOConsole(); */ public IOConsole() { consoleModel = createConsoleModel(); consoleModel.setConsole(this); setBackground(Color.WHITE); setInputColor(Color.BLUE); setInputStyle(Font.BOLD); setErrorColor(Color.RED); setErrorStyle(Font.BOLD); setFont(JTFTools.getStandardFont(DEFAULT_FONT)); Component consolePane = consoleModel.getConsolePane(); if (consolePane != null) { setLayout(new BorderLayout()); add(consolePane, BorderLayout.CENTER); } reader = null; writer = null; exceptionOnError = false; } /* Method: clear() */ /** * Clears the console display. * * Example: console.clear(); */ public void clear() { consoleModel.clear(); } /* 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: console.print(value); * @param value The value to be displayed */ public void print(String value) { getWriter().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: console.println(); */ public void println() { getWriter().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: console.println(value); * @param value The value to be displayed */ public void println(String value) { getWriter().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 on the console. * * Example: console.showErrorMessage(msg); * @param msg The error msg to be displayed */ public void showErrorMessage(String msg) { consoleModel.print(msg, ConsoleModel.ERROR_STYLE); consoleModel.print("\n", ConsoleModel.ERROR_STYLE); } /* Method: readLine() */ /** * Reads and returns a line of input from the console, without * including the end-of-line characters that terminate the input. * * Example: String str = console.readLine(); * @return The next line of input as a String */ public final String readLine() { return readLine(null); } /* Method: readLine(prompt) */ /** * Prompts the user to enter a line of text, which is then returned * as the value of this method. The end-of-line characters that terminate * the input are not included in the returned string. * * Example: String str = console.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) { if (prompt != null) print(prompt); consoleModel.requestFocus(); try { String str = getReader().readLine(); return str; } catch (IOException ex) { throw new ErrorException(ex); } } /* 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 = console.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 = console.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 = console.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) { String msg = null; while (true) { String line = readLine(prompt); try { int n = Integer.parseInt(line); if (n >= low && n <= high) return n; msg = "Value is outside the range [" + low + ":" + high + "]"; } catch (NumberFormatException ex) { msg = "Illegal numeric format"; } showErrorMessage(msg); if (prompt == null) prompt = "Retry: "; } } /* 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 = console.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 = console.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 = console.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 = console.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) { String msg = null; while (true) { String line = readLine(prompt); try { double d = Double.valueOf(line).doubleValue(); if (d >= low && d <= high) return d; msg = "Value is outside the range [" + low + ":" + high + "]"; } catch (NumberFormatException ex) { msg = "Illegal numeric format"; } showErrorMessage(msg); if (prompt == null) prompt = "Retry: "; } } /* Method: readBoolean() */ /** * Reads and returns a boolean value from the user, which must match * either true or false, 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 = console.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 then 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 = console.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 value, which is interpreted as a boolean value * by matching it against the trueLabel and falseLabel * parameters. If the user types 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 = console.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) { while (true) { String line = readLine(prompt); if (line == null) { throw new ErrorException("End of file encountered"); } else if (line.equalsIgnoreCase(trueLabel)) { return true; } else if (line.equalsIgnoreCase(falseLabel)) { return false; } else { if (exceptionOnError) { throw new ErrorException("Illegal boolean format"); } showErrorMessage("Illegal boolean format"); if (prompt == null) prompt = "Retry: "; } } } /* Method: getReader() */ /** * Returns a BufferedReader object that can be used to read * from the console. * * Example: BufferedReader rd = console.getReader(); * @return A BufferedReader that reads from this console */ public BufferedReader getReader() { if (reader == null) { reader = new BufferedReader(new ConsoleReader(consoleModel)); } return reader; } /* Method: getWriter() */ /** * Returns a PrintWriter object that can be used to send * output to the console. * * Example: PrintWriter wr = console.getWriter(); * @return A PrintWriter that writes to this console */ public PrintWriter getWriter() { if (writer == null) { writer = new PrintWriter(new ConsoleWriter(consoleModel)); } return writer; } /* Method: setExceptionOnError(flag) */ /** * Sets the error-handling mode of the console as specified by the flag * parameter. If flag is false (which is the default), the * input methods give the user a chance to retry after erroneous input. If this * value is set to true, illegal input raises an * ErrorException instead. * * Example: console.setExceptionOnError(flag); * @param flag false to retry on errors; true to raise an exception */ public void setExceptionOnError(boolean flag) { exceptionOnError = flag; } /* Method: getExceptionOnError() */ /** * Returns the state of the error-handling flag. * * Example: boolean flag = console.getExceptionOnError(); * @return The current setting of the error-handling mode (false to retry * on errors; true to raise an exception) */ public boolean getExceptionOnError() { return exceptionOnError; } /* Method: setInputStyle(style) */ /** * Sets the style parameters for console input. The style parameter * is either Font.PLAIN or a sum of one or more of the attributes * Font.BOLD and Font.ITALIC. * * Example: console.setInputStyle(style); * @param style The style attributes to be used for console input * */ public void setInputStyle(int style) { inputStyle = style; consoleModel.setInputStyle(style); } /* Method: getInputStyle() */ /** * Returns the current style parameters for console input. * * Example: int style = console.getInputStyle(); * @return The current input style * */ public int getInputStyle() { return inputStyle; } /* Method: setInputColor(color) */ /** * Sets the color used for console input. * * Example: console.setInputColor(color); * @param color The color used for console input * */ public void setInputColor(Color color) { inputColor = color; consoleModel.setInputColor(color); } /* Method: getInputColor() */ /** * Returns the color currently in use for console input. * * Example: Color color = console.getInputColor(); * @return The current input color * */ public Color getInputColor() { return inputColor; } /* Method: setErrorStyle(style) */ /** * Sets the style parameters for console error messages. The style parameter * is either Font.PLAIN or a sum of one or more of the attributes * Font.BOLD and Font.ITALIC. * * Example: console.setErrorStyle(style); * @param style The style attributes to be used for console error messages * */ public void setErrorStyle(int style) { errorStyle = style; consoleModel.setErrorStyle(style); } /* Method: getErrorStyle() */ /** * Returns the current style parameters for console error messages. * * Example: int style = console.getErrorStyle(); * @return The current error message style * */ public int getErrorStyle() { return errorStyle; } /* Method: setErrorColor(color) */ /** * Sets the color used for console error messages. * * Example: console.setErrorColor(color); * @param color The color used for console error messages * */ public void setErrorColor(Color color) { errorColor = color; consoleModel.setErrorColor(color); } /* Method: getErrorColor() */ /** * Returns the color currently in use for console error messages. * * Example: Color color = console.getErrorColor(); * @return The current error message color * */ public Color getErrorColor() { return errorColor; } /* Method: setFont(str) */ /** * Sets the font used for the console as specified by * the string str, which is interpreted in the style of * Font.decode. The usual format of the font string is * *

 

family-style-size

 

* * where both style and size are optional. If any of these parts * are specified as an asterisk, the existing value is retained. * * Example: console.setFont(str); * @param str A String specifying the new font */ public void setFont(String str) { setFont(JTFTools.decodeFont(str, getFont())); } /* Method: setInputScript(rd) */ /** * Sets a new input script for the console, which will subsequently * take input from the specified reader. When the input from the reader * has been exhausted, the console returns to its normal operation. This * method is primarily useful for demonstrations and test suites, and is * not ordinarily invoked by students. * * Example: console.setInputScript(rd); * @param rd The reader from which console input is taken * */ public void setInputScript(BufferedReader rd) { consoleModel.setInputScript(rd); } /* Method: getInputScript() */ /** * Retrieves the input script. After the end of the input script has been * reached, this method will return null. * * Example: BufferedReader rd = console.getInputScript(); * @return The reader representing the current input script */ public BufferedReader getInputScript() { return consoleModel.getInputScript(); } /* Method: cut() */ /** * Implements the "Cut" menu operation. * * Example: console.cut(); * */ public void cut() { consoleModel.cut(); } /* Method: copy() */ /** * Implements the "Copy" menu operation. * * Example: console.copy(); * */ public void copy() { consoleModel.copy(); } /* Method: paste() */ /** * Implements the "Paste" menu operation. * * Example: console.paste(); * */ public void paste() { consoleModel.paste(); } /* Method: selectAll() */ /** * Implements the "Select All" menu operation. * * Example: console.selectAll(); * */ public void selectAll() { consoleModel.selectAll(); } /* Method: save() */ /** * Implements the "Save" menu operation. * * Example: console.save(); * */ public void save() { Writer wr = null; while (wr == null) { try { if (file == null) { Frame frame = JTFTools.getEnclosingFrame(this); if (frame == null) return; String dir = System.getProperty("user.dir"); FileDialog dialog = new FileDialog(frame, "Save Console As", FileDialog.SAVE); dialog.setDirectory(dir); dialog.setVisible(true); String filename = dialog.getFile(); if (filename == null) return; file = new File(dialog.getDirectory(), filename); } wr = new FileWriter(file); save(wr); wr.close(); Platform.setFileTypeAndCreator(file, "TEXT", "ttxt"); } catch (IOException ex) { IODialog dialog = new IODialog(this); dialog.showErrorMessage(ex.getMessage()); } } } /* Method: saveAs() */ /** * Implements the "Save As" menu operation. * * Example: console.saveAs(); * */ public void saveAs() { file = null; save(); } /* Method: save(wr) */ /** * Copies the console output to the specified writer. * * Example: console.save(wr); * @param wr A Writer to which the console output is sent * */ public void save(Writer wr) { try { wr.write(consoleModel.getText()); } catch (IOException ex) { throw new ErrorException(ex); } } /* Method: printConsole() */ /** * Implements the "Print Console" menu operation. * * Example: console.printConsole(); * */ public void printConsole() { Frame frame = JTFTools.getEnclosingFrame(this); if (frame == null) return; PrintJob pj = getToolkit().getPrintJob(frame, "Console", null); if (pj == null) return; printConsole(pj); pj.end(); } /* Method: printConsole(pj) */ /** * Prints the console output using the specified PrintJob object. * This method is usually invoked from the Print menu item in * the ProgramMenuBar class and is not ordinarily called by clients. * * Example: console.printConsole(pj); * @param pj PrintJob object to which the output is sent * */ public void printConsole(PrintJob pj) { consoleModel.print(pj); } /* Method: script() */ /** * Implements the "Script" menu operation. * * Example: console.script(); * */ public void script() { Frame frame = JTFTools.getEnclosingFrame(this); FileDialog dialog = new FileDialog(frame, "Input Script", FileDialog.LOAD); dialog.setDirectory(System.getProperty("user.dir")); dialog.setVisible(true); String dirname = dialog.getDirectory(); String filename = dialog.getFile(); if (filename != null) { try { FileReader rd = new FileReader(new File(new File(dirname), filename)); setInputScript(new BufferedReader(rd)); } catch (IOException ex) { throw new ErrorException(ex); } } } /* Method: setMenuBar(mbar) */ /** * Sets the menu bar that controls this console. * * Example: console.setMenuBar(mbar); * @param mbar The menu bar */ public void setMenuBar(ProgramMenuBar mbar) { menuBar = mbar; consoleModel.setMenuBar(mbar); } /* Method: getMenuBar() */ /** * Returns the menu bar that controls this console. * * Example: ProgramMenuBar mbar = console.getMenuBar(); * @return The menu bar */ public ProgramMenuBar getMenuBar() { return menuBar; } /* Method: menuAction(e) */ /** * Called whenever a relevant action is detected in the menu bar. * Subclasses can override this method to extend the set of menu * commands recognized by the console. * * @param e event * @return true if handled */ public boolean menuAction(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals("Cut")) { cut(); return true; } else if (cmd.equals("Copy")) { copy(); return true; } else if (cmd.equals("Paste")) { paste(); return true; } else if (cmd.equals("Select All")) { selectAll(); return true; } else if (cmd.equals("Save")) { save(); return true; } else if (cmd.equals("Save As")) { saveAs(); return true; } else if (cmd.equals("Script")) { script(); return true; } else if (cmd.equals("Print Console")) { printConsole(); return true; } return false; } /* Method: isConsoleMenuItem(item) */ /** * @param item menu item * @return Returns true if the item is one that the console recognizes. */ public boolean isConsoleMenuItem(JMenuItem item) { String cmd = item.getActionCommand(); if (cmd == null) return false; for (int i = 0; i < CONSOLE_MENU_ACTIONS.length; i++) { if (cmd.equals(CONSOLE_MENU_ACTIONS[i])) return true; } return false; } /* Method: updateMenuBar(mbar) */ /** * @param mbar Updates the menu bar to enable the appropriate menu items. */ public void updateMenuBar(ProgramMenuBar mbar) { Iterator iterator = mbar.iterator(); while (iterator.hasNext()) { JMenuItem item = iterator.next(); if (isConsoleMenuItem(item)) { item.setEnabled(true); } else { item.setEnabled(!mbar.isFocusedItem(item)); } } } /* Override method: setBackground(color) */ /** * Sets the background color used for the console. * * Example: console.setBackground(color); * @param color The new background color */ public void setBackground(Color color) { Component textPane = consoleModel.getTextPane(); if (textPane != null) textPane.setBackground(color); super.setBackground(color); } /* Override method: setForeground(color) */ /** * Sets the foreground color used for the output text. * * Example: console.setForeground(color); * @param color The color to use for the output text */ public void setForeground(Color color) { Component textPane = consoleModel.getTextPane(); if (textPane != null) textPane.setForeground(color); super.setForeground(color); } /* Override method: setFont(font) */ /** * Sets the font for the console. * * Example: console.setFont(font); * @param font The font to use for the console */ public void setFont(Font font) { font = JTFTools.getStandardFont(font); Component textPane = consoleModel.getTextPane(); if (textPane != null) textPane.setFont(font); super.setFont(font); } /* Override method: requestFocus() */ /** * Overrides the requestFocus method so that it forwards to the * console model. * * Example: console.requestFocus(); * */ public void requestFocus() { consoleModel.requestFocus(); } /* Override method: getPreferredSize() */ /** * Overrides the getPreferredSize method to ensure that an * IOConsole is not too large. * * Example: Dimension size = console.getPreferredSize(); * */ public Dimension getPreferredSize() { return getMinimumSize(); } /* Override method: getMinimumSize() */ /** * Overrides the getMinimumSize method to ensure that an * IOConsole is not too large. * * Example: Dimension size = console.getMinimumSize(); * */ public Dimension getMinimumSize() { return new Dimension(MINIMUM_CONSOLE_WIDTH, MINIMUM_CONSOLE_HEIGHT); } /* Protected method: createConsoleModel() */ /** * @return Creates the console model used by this console. */ protected ConsoleModel createConsoleModel() { return new StandardConsoleModel(); } /* Protected constant: DEFAULT_FONT */ /** * The default font used by a new IOConsole. */ protected static final Font DEFAULT_FONT = new Font("Monospaced", Font.PLAIN, 12); /* Protected constant: LINE_SEPARATOR */ /** * The end-of-line separator for this platform. */ protected static final String LINE_SEPARATOR = System.getProperty("line.separator"); /* Protected constant: MINIMUM_CONSOLE_WIDTH */ /** * The minimum width for a console. */ protected static final int MINIMUM_CONSOLE_WIDTH = 50; /* Protected constant: MINIMUM_CONSOLE_HEIGHT */ /** * The minimum height for a console. */ protected static final int MINIMUM_CONSOLE_HEIGHT = 40; /* Private constants */ private static final String[] CONSOLE_MENU_ACTIONS = { "Save", "Save As", "Print Console", "Script", "Cut", "Copy", "Paste", "Select All" }; /* Private instance variables */ private ConsoleModel consoleModel; private boolean exceptionOnError; private Color inputColor; private int inputStyle; private Color errorColor; private int errorStyle; private BufferedReader reader; private PrintWriter writer; private File file; private ProgramMenuBar menuBar; } /* Package interface: ConsoleModel */ /** * This interface defines the operations that any console model must implement. */ interface ConsoleModel { /* Constants for display types */ public static final int OUTPUT_STYLE = 0; public static final int INPUT_STYLE = 1; public static final int ERROR_STYLE = 2; /* Method signatures */ public void setConsole(IOConsole owner); public IOConsole getConsole(); public void print(String str, int style); public String readLine(); public void setInputScript(BufferedReader rd); public BufferedReader getInputScript(); public void clear(); public String getText(); public String getText(int start, int end); public int getLength(); public Component getConsolePane(); public Component getTextPane(); public void cut(); public void copy(); public void paste(); public void selectAll(); public boolean isPointSelection(); public void print(PrintJob pj); public void setInputStyle(int style); public void setInputColor(Color color); public void setErrorStyle(int style); public void setErrorColor(Color color); public void requestFocus(); public void setMenuBar(ProgramMenuBar mbar); } /* Package class: StandardConsoleModel */ /** * This class implements the console model using Swing. */ class StandardConsoleModel implements KeyListener, FocusListener, ConsoleModel { /* Constructor: StandardConsoleModel() */ /** * Creates the framework for the standard console models. */ public StandardConsoleModel() { outputMonitor = new ConsoleOutputMonitor(this); inputMonitor = new ConsoleInputMonitor(this); scrollPane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); textPane = new JTextPane(); textPane.addKeyListener(this); textPane.addFocusListener(this); scrollPane.setViewportView(textPane); document = textPane.getDocument(); lineSeparator = System.getProperty("line.separator"); outputAttributes = new SimpleAttributeSet(); inputAttributes = new SimpleAttributeSet(); errorAttributes = new SimpleAttributeSet(); buffer = new CharacterQueue(); base = 0; } /* Method: setConsole(owner) */ /** * Sets the identity of the owning console. This method must be called after * creating the model object. */ public void setConsole(IOConsole owner) { console = owner; } /* Method: getConsole(console) */ /** * Returns the associated console. */ public IOConsole getConsole() { return console; } /* Method: print(str, style) */ /** * Prints the string to the console. */ public void print(String str, int style) { outputMonitor.print(str, style); } /* Method: readLine() */ /** * Reads and returns the next line of text from the console. */ public String readLine() { return inputMonitor.readLine(); } /* Method: setInputScript(rd) */ /** * Sets a new input script for the console, which will subsequently * take input from the specified reader. */ public void setInputScript(BufferedReader rd) { inputScript = rd; if (buffer.isWaiting()) { try { String line = inputScript.readLine(); buffer.enqueue(line + "\n"); } catch (IOException ex) { throw new ErrorException(ex); } } } /* Method: getInputScript() */ /** * Retrieves the input script. After the end of the input script has been * reached, this method will return null. */ public BufferedReader getInputScript() { return inputScript; } /* Method: clear() */ /** * Clears the console pane. */ public void clear() { textPane.setText(""); base = 0; buffer.clear(); } /* Method: getText() */ /** * Returns the text stored in the console model. */ public String getText() { return textPane.getText(); } /* Method: getText(start, end) */ /** * Returns a substring from the text using endpoints defined as in * substring for strings. */ public String getText(int start, int end) { try { return document.getText(start, end - start); } catch (BadLocationException ex) { throw new ErrorException(ex); } } /* Method: getLength() */ /** * Returns the length of the text stored in the console model. */ public int getLength() { return document.getLength(); } /* Method: getConsolePane() */ /** * Returns the top-level component that represents the console. This is the * pane that needs to be added to a parent. */ public Component getConsolePane() { return scrollPane; } /* Method: getTextPane() */ /** * Returns the component that holds the text. This is the pane to which * messages like setFont and requestFocus should * be directed. */ public Component getTextPane() { return textPane; } /* Method: cut() */ /** * Implements the "cut" menu operation. */ public void cut() { copy(); deleteSelection(); } /* Method: copy() */ /** * Implements the "copy" menu operation. */ public void copy() { textPane.copy(); } /* Method: paste() */ /** * Implements the "paste" menu operation. */ public void paste() { if (textPane.getSelectionEnd() != document.getLength()) return; int start = deleteSelection(); textPane.setSelectionStart(start); textPane.paste(); textPane.select(document.getLength(), document.getLength()); if (document instanceof DefaultStyledDocument) { DefaultStyledDocument doc = (DefaultStyledDocument) document; doc.setCharacterAttributes(start, textPane.getSelectionEnd() - start, inputAttributes, true); } } /* Method: selectAll() */ /** * Implements the "select all" menu operation. */ public void selectAll() { textPane.selectAll(); } /* Method: isPointSelection() */ public boolean isPointSelection() { return textPane.getSelectionStart() == textPane.getSelectionEnd(); } /* Method: print(pj) */ /** * Prints the entire console using the specified PrintJob object. */ public void print(PrintJob pj) { Graphics g = pj.getGraphics(); Dimension pageSize = pj.getPageDimension(); FontMetrics fm = textPane.getFontMetrics(textPane.getFont()); int fontHeight = fm.getHeight(); int fontAscent = fm.getAscent(); int x = PRINT_MARGIN; int y = PRINT_MARGIN + fontAscent; int linesPerPage = (pageSize.height - 2 * PRINT_MARGIN) / fontHeight; int linesRemaining = linesPerPage; ElementIterator i = new ElementIterator(document); while (true) { Element e = i.next(); if (e == null) break; if (e.isLeaf()) { try { int len = e.getEndOffset() - e.getStartOffset(); setStyleFromAttributes(g, e.getAttributes()); fm = g.getFontMetrics(); String text = document.getText(e.getStartOffset(), len); int start = 0; while (true) { boolean last = false; int delta = 1; int eol = text.indexOf("\n", start); if (eol == -1) { eol = text.indexOf(lineSeparator, start); if (eol == -1) { eol = text.length(); last = true; } else { delta = lineSeparator.length(); } } if (start < eol) { String str = text.substring(start, eol); g.drawString(str, x, y); x += fm.stringWidth(str); } if (last) break; start = eol + delta; x = PRINT_MARGIN; y += fontHeight; linesRemaining--; if (linesRemaining <= 0) { g.dispose(); g = pj.getGraphics(); y = PRINT_MARGIN + fontAscent; linesRemaining = linesPerPage; } } } catch (BadLocationException ex) { throw new ErrorException(ex); } } } pj.end(); } /* Method: setInputStyle(style) */ /** * Sets the style parameters for console input. The style parameter * is either Font.PLAIN or a sum of one or more of the attributes * Font.BOLD and Font.ITALIC. */ public void setInputStyle(int style) { if (getLength() != 0) { throw new ErrorException("Console styles and colors cannot be changed after I/O has started."); } inputAttributes.addAttribute(StyleConstants.Bold, new Boolean((style & Font.BOLD) != 0)); inputAttributes.addAttribute(StyleConstants.Italic, new Boolean((style & Font.ITALIC) != 0)); } /* Method: setInputColor(color) */ /** * Sets the color used for console input. */ public void setInputColor(Color color) { if (getLength() != 0) { throw new ErrorException("Console styles and colors cannot be changed after I/O has started."); } inputAttributes.addAttribute(StyleConstants.Foreground, color); } /* Method: setErrorStyle(style) */ /** * Sets the style parameters for console error messages. The style parameter * is either Font.PLAIN or a sum of one or more of the attributes * Font.BOLD and Font.ITALIC. */ public void setErrorStyle(int style) { if (getLength() != 0) { throw new ErrorException("Console styles and colors cannot be changed after I/O has started."); } errorAttributes.addAttribute(StyleConstants.Bold, new Boolean((style & Font.BOLD) != 0)); errorAttributes.addAttribute(StyleConstants.Italic, new Boolean((style & Font.ITALIC) != 0)); } /* Method: setErrorColor(color) */ /** * Sets the color used for console error. */ public void setErrorColor(Color color) { if (getLength() != 0) { throw new ErrorException("Console styles and colors cannot be changed after I/O has started."); } errorAttributes.addAttribute(StyleConstants.Foreground, color); } /* Method: requestFocus() */ /** * Forwards the request focus to the text pane. * */ public void requestFocus() { if (textPane != null) textPane.requestFocus(); } /* Method: setMenuBar(mbar) */ /** * Sets the menu bar that controls this console. * */ public void setMenuBar(ProgramMenuBar mbar) { menuBar = mbar; } /* Implementation of the FocusListener interface */ /* Method: focusGained */ /** * Called when focus is gained by the console. */ public void focusGained(FocusEvent e) { hasFocus = true; if (menuBar != null) { if (actionListener == null) { actionListener = new ConsoleActionListener(console); } menuBar.setFocusedListener(actionListener); console.updateMenuBar(menuBar); } } /* Method: focusLost */ /** * Called when focus is lost by the console. */ public void focusLost(FocusEvent e) { hasFocus = false; if (menuBar != null) { menuBar.setFocusedListener(null); } } /* Implementation of the KeyListener interface */ /* Method: keyTyped(e) */ /** * Responds to a key being typed in the console pane. Implements KeyListener. */ public void keyTyped(KeyEvent e) { if (!e.isMetaDown() && !e.isControlDown()) { buffer.enqueue(e.getKeyChar()); e.consume(); } } /* Method: keyPressed(e) */ /** * Responds to key presses that do not correspond to typed keys. * Implements KeyListener. */ public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: buffer.enqueue('\002'); break; case KeyEvent.VK_RIGHT: buffer.enqueue('\006'); break; } if (menuBar != null) menuBar.fireAccelerator(e); e.consume(); } /* Method: keyReleased(e) */ /** * Responds to the release of a key. Implements KeyListener. * */ public void keyReleased(KeyEvent e) { e.consume(); } /* Protected method: printCallback(str, style) */ /** * Prints the string to the console. Synchronization is provided by * the ConsoleOutputMonitor class. */ protected void printCallback(String str, int style) { insert(str, base, style); base += str.length(); setCaretPosition(base); } /* Protected method: readLineCallback() */ /** * Reads and returns the next line of text from the console. * Synchronization is provided by the ConsoleInputMonitor class. */ protected String readLineCallback() { base = getLength(); if (inputScript != null) { String line = null; try { line = inputScript.readLine(); } catch (IOException ex) { throw new ErrorException(ex); } if (line != null) { insert(line, base, INPUT_STYLE); insert("\n", base + line.length(), OUTPUT_STYLE); base += line.length() + 1; return line; } try { inputScript.close(); } catch (IOException ex) { /* Empty */ } inputScript = null; } int dot; char ch; setCaretPosition(base); while ((ch = buffer.dequeue()) != '\n' && ch != '\r') { if (getCaretPosition() < base) { setCaretPosition(getLength()); } dot = getSelectionStart(); switch (ch) { case '\b': case '\177': if (dot == getSelectionEnd()) { if (dot > base) { delete(dot - 1, dot); dot--; } } else { dot = deleteSelection(); } break; case 'A'-'@': selectAll(); dot = -1; break; case 'B'-'@': dot = Math.max(getSelectionStart() - 1, base); break; case 'C'-'@': copy(); dot = -1; break; case 'F'-'@': dot = Math.min(getSelectionEnd() + 1, getLength()); break; case 'P'-'@': console.printConsole(); dot = -1; break; case 'S'-'@': console.save(); dot = -1; break; case 'V'-'@': paste(); dot = -1; break; case 'X'-'@': cut(); dot = -1; break; default: if (dot != getSelectionEnd()) { dot = deleteSelection(); } insert("" + ch, dot, INPUT_STYLE); dot++; } if (dot != -1) { select(dot, dot); setCaretPosition(dot); } } int len = getLength() - base; String line = getText(base, base + len); insert("\n", base + len, OUTPUT_STYLE); base += len + 1; return line; } /* Private method: isCommandEnabled(cmd) */ /** * Returns true if the command should be enabled in the menu bar. */ public boolean isCommandEnabled(String cmd) { if (cmd == cmd) /* Avoid unused parameter warning */; return hasFocus; } /* Private method: insert(str, dot, style) */ /** * Inserts a string into the text pane at the position specified by dot, * using the specified style. */ private void insert(String str, int dot, int style) { try { SimpleAttributeSet attributes = outputAttributes; switch (style) { case INPUT_STYLE: attributes = inputAttributes; break; case ERROR_STYLE: attributes = errorAttributes; break; } document.insertString(dot, str, attributes); } catch (BadLocationException ex) { /* Empty */ } } /* Private method: delete(p1, p2) */ /** * Deletes text from the text pane beginning at position p1 and * continuing up to but not including p2. */ private void delete(int p1, int p2) { try { document.remove(p1, p2 - p1); } catch (BadLocationException ex) { throw new ErrorException(ex); } } /* Private method: setCaretPosition(pos) */ /** * Sets the position of the input carat. */ private void setCaretPosition(int pos) { textPane.setCaretPosition(pos); } /* Private method: getCaretPosition() */ /** * Returns the position of the input carat. */ private int getCaretPosition() { return textPane.getCaretPosition(); } /* Private method: select(p1, p2) */ /** * Selects the characters in the range from p1 up to but not including p2. */ private void select(int p1, int p2) { textPane.select(p1, p2); } /* Private method: getSelectionStart() */ /** * Returns the start of the selection. */ private int getSelectionStart() { return textPane.getSelectionStart(); } /* Private method: getSelectionEnd() */ /** * Returns the end of the selection. */ private int getSelectionEnd() { return textPane.getSelectionEnd(); } /* Private method: deleteSelection() */ /** * Deletes the current selection and returns the index of the deletion point. */ private int deleteSelection() { int start = Math.max(base, getSelectionStart()); int end = getSelectionEnd(); if (end <= base) return getLength(); delete(start, end); return start; } /* Private method: setStyleFromAttributes(g, attributes) */ /** * Sets the relevant components of the graphics context from the attribute set. */ private void setStyleFromAttributes(Graphics g, AttributeSet attributes) { Font oldFont = textPane.getFont(); int style = 0; if (Boolean.TRUE.equals(attributes.getAttribute(StyleConstants.Bold))) { style |= Font.BOLD; } if (Boolean.TRUE.equals(attributes.getAttribute(StyleConstants.Italic))) { style |= Font.ITALIC; } g.setFont(new Font(oldFont.getName(), style, oldFont.getSize())); Color color = (Color) attributes.getAttribute(StyleConstants.Foreground); if (color == null) color = textPane.getForeground(); g.setColor(color); } /* Private constants */ private static final int PRINT_MARGIN = 36; /* Private instance variables */ private ActionListener actionListener; private ConsoleOutputMonitor outputMonitor; private ConsoleInputMonitor inputMonitor; private BufferedReader inputScript; private CharacterQueue buffer; private SimpleAttributeSet outputAttributes; private SimpleAttributeSet inputAttributes; private SimpleAttributeSet errorAttributes; private JScrollPane scrollPane; private JTextPane textPane; private Document document; private String lineSeparator; private int base; private boolean hasFocus; private IOConsole console; private ProgramMenuBar menuBar; } /* Package class: ConsoleOutputMonitor */ /** * This class implements synchronization for the output side of the console * using method-level synchronization, thereby avoiding the compatibility * problems of the synchronized statement. */ class ConsoleOutputMonitor { /* Constructor: new ConsoleOutputMonitor(model) */ /** * Creates the new console output monitor, which calls back to the specified * model. */ public ConsoleOutputMonitor(StandardConsoleModel model) { consoleModel = model; } /* Method: print(str, style) */ /** * Prints the string to the console. */ public synchronized void print(String str, int style) { consoleModel.printCallback(str, style); } /* Private instance variables */ private StandardConsoleModel consoleModel; } /* Package class: ConsoleInputMonitor */ /** * This class implements synchronization for the input side of the console * using method-level synchronization, thereby avoiding the compatibility * problems of the synchronized statement. */ class ConsoleInputMonitor { /* Constructor: new ConsoleInputMonitor(model) */ /** * Creates the new console input monitor, which calls back to the specified * model. */ public ConsoleInputMonitor(StandardConsoleModel model) { consoleModel = model; } /* Method: readLine() */ /** * Reads and returns the next line of text from the console. */ public synchronized String readLine() { return consoleModel.readLineCallback(); } /* Private instance variables */ private StandardConsoleModel consoleModel; } /* Package class: SystemConsole */ /** * This class implements a version of IOConsole that responds to * the methods of that class but that uses System.in and * System.out for its input and output. This class is not * instantiated directly; clients gain access to this facility by using the * SYSTEM_CONSOLE * constant in the IOConsole class. */ class SystemConsole extends IOConsole { /* Factory method: createConsoleModel() */ /** * Creates the console model object used to implement this console. */ protected ConsoleModel createConsoleModel() { return new SystemConsoleModel(); } } /* Package class: ConsoleWriter */ /** * This class defines the underlying writer for the console. * */ class ConsoleWriter extends Writer { /* Constructor: ConsoleWriter(cp) */ /** * Creates the basic writer object for the console. */ public ConsoleWriter(ConsoleModel cp) { consoleModel = cp; } /* Method: close() */ /** * Closes the writer (does nothing in this case). */ public void close() { /* Empty */ } /* Method: flush() */ /** * Flushes any remaining output to the writer. */ public void flush() { /* Empty */ } /* Method: write(cbuf, off, len) */ /** * Writes characters from cbuf starting at position off * up to a maximum of len. */ public void write(char[] cbuf, int off, int len) { String str = new String(cbuf, off, len); int start = 0; int eol; while ((eol = str.indexOf(IOConsole.LINE_SEPARATOR, start)) != -1) { consoleModel.print(str.substring(start, eol), ConsoleModel.OUTPUT_STYLE); consoleModel.print("\n", ConsoleModel.OUTPUT_STYLE); start = eol + IOConsole.LINE_SEPARATOR.length(); } consoleModel.print(str.substring(start), ConsoleModel.OUTPUT_STYLE); } /* Private instance variables */ private ConsoleModel consoleModel; } /* Package class: ConsoleReader */ /** * This class defines the underlying reader for the console. */ class ConsoleReader extends Reader { /* Constructor: ConsoleReader(cp) */ /** * Creates the basic reader object for the console. */ public ConsoleReader(ConsoleModel cp) { consoleModel = cp; buffer = null; } /* Method: close() */ /** * Closes the reader (does nothing in this case). */ public void close() { /* Empty */ } /* Method: read(cbuf, off, len) */ /** * Reads characters into cbuf starting at position off * up to a maximum of len. */ public int read(char[] cbuf, int off, int len) { if (len == 0) return 0; if (buffer == null) { buffer = consoleModel.readLine(); if (buffer == null) return -1; buffer += "\n"; } if (len < buffer.length()) { buffer.getChars(0, len, cbuf, off); buffer = buffer.substring(len); } else { len = buffer.length(); buffer.getChars(0, len, cbuf, off); buffer = null; } return len; } /* Private instance variables */ private ConsoleModel consoleModel; private String buffer; } /* Package class: SystemConsoleModel */ /** * Implements the basic console operations for the system console. */ class SystemConsoleModel implements ConsoleModel { /* Constructor: SystemConsoleModel() */ /** * Creates a new SystemConsoleModel object. */ public SystemConsoleModel() { text = ""; } /* Method: setConsole(owner) */ /** * Sets the identity of the owning console. This method must be called after * creating the model object. */ public void setConsole(IOConsole owner) { console = owner; } /* Method: getConsole(console) */ /** * Returns the associated console. */ public IOConsole getConsole() { return console; } /* Method: clear() */ /** * Clears the console pane. */ public void clear() { /* Empty */ } /* Method: print(str, style) */ /** * Prints the string to the end of the console output. */ public void print(String str, int style) { System.out.print(str); text += str; } /* Method: readLine() */ /** * Reads and returns the next line of text from the console. */ public String readLine() { System.out.flush(); String line = ""; int ch; try { while (true) { if (inputScript == null) { ch = System.in.read(); } else { ch = inputScript.read(); } if (ch == -1 && line.length() == 0) { try { if (inputScript != null) inputScript.close(); } catch (IOException ex) { /* Empty */ } inputScript = null; } else { if (ch == -1 || ch == '\n') break; line += (char) ch; } } } catch (IOException ex) { /* Empty */ } if (inputScript != null) print(line + "\n", INPUT_STYLE); return line; } /* Method: getText() */ /** * Returns the text stored in the console pane. */ public String getText() { return text; } /* Method: getText(start, end) */ /** * Returns a substring from the text using endpoints defined as in * substring for strings. */ public String getText(int start, int end) { return text.substring(start, end); } /* Method: getLength() */ /** * Returns the length of the text. */ public int getLength() { return text.length(); } /* Method: getConsoleModel() */ /** * Returns the top-level component that represents the console. This is the * pane that needs to be added to a parent. */ public Component getConsoleModel() { return null; } /* Method: getTextPane() */ /** * Returns the component that holds the text. This is the model to which * messages like setFont and requestFocus should * be directed. */ public Component getTextPane() { return null; } /* Method: setFont(font) */ /** * Sets the font for the console. * * Example: consoleModel.setFont(font); * @param font The new font for the console */ public void setFont(Font font) { if (font != font); /* Avoid unused parameter warning */; /* Empty */ } /* Method: setInputStyle(style) */ /** * Sets the style parameters for console input. The style parameter * is either Font.PLAIN or a sum of one or more of the attributes * Font.BOLD and Font.ITALIC. */ public void setInputStyle(int style) { /* Empty */ } /* Method: setInputColor(color) */ /** * Sets the color used for console input. */ public void setInputColor(Color color) { /* Empty */ } /* Method: setErrorStyle(style) */ /** * Sets the style parameters for console error messages. The style parameter * is either Font.PLAIN or a sum of one or more of the attributes * Font.BOLD and Font.ITALIC. */ public void setErrorStyle(int style) { /* Empty */ } /* Method: setErrorColor(color) */ /** * Sets the color used for console error messages. */ public void setErrorColor(Color color) { /* Empty */ } /* Method: cut() */ /** * Implements the "cut" menu operation. */ public void cut() { /* Empty */ } /* Method: copy() */ /** * Implements the "copy" menu operation. */ public void copy() { /* Empty */ } /* Method: paste() */ /** * Implements the "paste" menu operation. */ public void paste() { /* Empty */ } /* Method: selectAll() */ /** * Implements the "select all" menu operation. */ public void selectAll() { /* Empty */ } /* Method: isPointSelection() */ public boolean isPointSelection() { return true; } /* Method: print(pj) */ /** * Prints the entire console using the specified PrintJob object. */ public void print(PrintJob pj) { /* Empty */ } /* Method: setInputScript(rd) */ /** * Sets a new input script for the console, which will subsequently * take input from the specified reader. */ public void setInputScript(BufferedReader rd) { inputScript = rd; } /* Method: getInputScript() */ /** * Retrieves the input script. After the end of the input script has been * reached, this method will return null. */ public BufferedReader getInputScript() { return inputScript; } /* Method: getConsolePane() */ /** * Returns the top-level component that represents the console. */ public Component getConsolePane() { return null; } /* Method: requestFocus() */ /** * Forwards the request focus to the text pane. * */ public void requestFocus() { /* Empty */ } /* Method: setMenuBar(mbar) */ /** * Sets the menu bar that controls this console. * */ public void setMenuBar(ProgramMenuBar mbar) { /* Empty */ } /* Private instance variables */ private IOConsole console; private BufferedReader inputScript; private String text; } /* Package class: CharacterQueue */ /** * This class defines a simple character queue. */ class CharacterQueue { /* Constructor: CharacterQueue() */ /** * Creates an empty character queue. */ public CharacterQueue() { buffer = ""; } /* Method: enqueue(ch) */ /** * Adds a character to the end of the queue. */ public synchronized void enqueue(char ch) { buffer += ch; notifyAll(); } /* Method: enqueue(str) */ /** * Adds a string to the end of the queue. */ public synchronized void enqueue(String str) { buffer += str; notifyAll(); } /* Method: dequeue() */ /** * Removes and returns the first character in the queue. If the queue * is empty, this method waits for data. */ public synchronized char dequeue() { while (buffer.length() == 0) { try { isWaiting = true; wait(); isWaiting = false; } catch (InterruptedException ex) { /* Empty */ } } char ch = buffer.charAt(0); buffer = buffer.substring(1); return ch; } /* Method: clear() */ /** * Clears the character queue. */ public synchronized void clear() { buffer = ""; notifyAll(); } /* Method: isWaiting() */ /** * Returns true if the buffer is in a waiting state. */ public boolean isWaiting() { return isWaiting; } /* Private instance variables */ private String buffer; private boolean isWaiting; } /* Package class: ConsoleActionListener */ /** * This class listens for menu bar actions directed toward the console. */ class ConsoleActionListener implements ActionListener { /* Constructor: ConsoleActionListener(owner) */ /** * Creates a new action listener for the specified console. */ public ConsoleActionListener(IOConsole owner) { console = owner; } /* Method: actionPerformed(e) */ /** * Responds to the specified action event. */ public void actionPerformed(ActionEvent e) { console.menuAction(e); } /* Private instance variables */ private IOConsole console; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy