samer@0: /*
samer@0: * Shell.java
samer@0: *
samer@0: * Copyright (c) 2000, Samer Abdallah, King's College London.
samer@0: * All rights reserved.
samer@0: *
samer@0: * This software is provided AS IS and WITHOUT ANY WARRANTY;
samer@0: * without even the implied warranty of MERCHANTABILITY or
samer@0: * FITNESS FOR A PARTICULAR PURPOSE.
samer@0: */
samer@0:
samer@0: package samer.core;
samer@0: import java.io.*;
samer@0: import java.awt.*;
samer@0: import java.awt.event.*;
samer@0: import java.util.*;
samer@0:
samer@0: import samer.core.Environment.Datum;
samer@0: import samer.core.Environment.Binding;
samer@0: import samer.core.Environment.Autocoder;
samer@0:
samer@0:
samer@0:
samer@0: /**
samer@0: This class provides a set of static methods for
samer@0: some useful services. The actual implementation is
samer@0: provided by some object that implements the
samer@0: Shell.Interface interface.
samer@0: */
samer@0:
samer@0: public class Shell
samer@0: {
samer@0: /** All shells must implement this interface. It provides service that
samer@0: * are generally useful but can be implemented in different ways, such
samer@0: * as printing messages and getting usable windows. */
samer@0:
samer@0: public interface Interface
samer@0: {
samer@0: // different types of message
samer@0: void print(String msg);
samer@0: void status(String msg);
samer@0: void trace(String msg);
samer@0:
samer@0: // factory methods
samer@0: PrintWriter getPrintWriter();
samer@0: Window getWindow(String title);
samer@0: Dialog getDialog(String title);
samer@0:
samer@0: Container createButtonsFor(Agent agent);
samer@0: Viewer createViewerPanel(Viewer vwr);
samer@0: Component createLabel(String nm);
samer@0:
samer@0: NumberViewer createNumberViewer( String label, int flags, NumberSink s);
samer@0:
samer@0: // agents and viewables
samer@0: void registerViewable(Viewable v);
samer@0: void deregisterViewable(Viewable v);
samer@0: void registerAgent(Agent a);
samer@0: void deregisterAgent(Agent a);
samer@0: void exposeCommands(Agent agent);
samer@0: void exit();
samer@0: }
samer@0:
samer@0:
samer@0: /**
samer@0: Interface returned by the getWindow method of the
samer@0: Shell.Interface interface. The window is not necessarily
samer@0: visible on return -- use the expose()
samer@0: method to make it so.
samer@0: NB: distinct from java.awt.Window.
samer@0: */
samer@0:
samer@0: public interface Window {
samer@0: /** Make window visible */
samer@0: void expose();
samer@0:
samer@0: /** Hide and destroy window */
samer@0: void dispose();
samer@0:
samer@0: /** Should behave just like in java.awt.Window
*/
samer@0: void addWindowListener(WindowListener wl);
samer@0:
samer@0: /** Returns the AWT container for this window, in to
samer@0: which components can be added in the normal way */
samer@0: Container container();
samer@0: }
samer@0:
samer@0: /**
samer@0: Interface returned by the getDialog method of the
samer@0: Shell.Interface interface. The dialog is not necessarily
samer@0: visible on return -- use the expose()
samer@0: method to make it so.
samer@0:
A dialog is distinct from a window in that it samer@0: is modal, and is dismissed by one of a set of buttons. samer@0:
NB: distinct from java.awt.Dialog
samer@0: */
samer@0:
samer@0: public interface Dialog {
samer@0: /** Make dialog visible */
samer@0: void expose();
samer@0:
samer@0: /** Hide and destroy dialog */
samer@0: void dispose();
samer@0:
samer@0: /** Typically, the dialog will add a new button with the
samer@0: given label. */
samer@0: void addAction(String cmd);
samer@0:
samer@0: /** Returns the text of the button used to dismiss the dialog */
samer@0: String result();
samer@0:
samer@0: /** Returns the AWT container for this window, in to
samer@0: which components can be added in the normal way */
samer@0: Container container();
samer@0: }
samer@0:
samer@0:
samer@0:
samer@0: // .......................................................
samer@0:
samer@0: /** Sets the static current shell to point to the given shell */
samer@0: public static void setShell(Interface sh) { current=sh; }
samer@0:
samer@0: public static void print(String msg) { current.print(msg); }
samer@0: public static void status(String msg) { current.status(msg); }
samer@0: public static void trace(String msg) { current.trace(msg); }
samer@0:
samer@0: public static PrintWriter getPrintWriter() { return current.getPrintWriter(); }
samer@0: public static Window getWindow(String title) { return current.getWindow(title); }
samer@0: public static Dialog getDialog(String title) { return current.getDialog(title); }
samer@0:
samer@0: /** Create and return a new Panel containing the given Viewer */
samer@0: public static Viewer createViewerPanel(Viewer v ) {
samer@0: return current.createViewerPanel(v);
samer@0: }
samer@0:
samer@0: /** Return an AWT Container containing buttons for each the
samer@0: commands reported by the given Agent */
samer@0: public static Container createButtonsFor(Agent a) {
samer@0: return current.createButtonsFor(a);
samer@0: }
samer@0:
samer@0: /** Return a label component. Can be AWT, Swing, or whatever */
samer@0: public static Component createLabel(String txt) {
samer@0: return current.createLabel(txt);
samer@0: }
samer@0:
samer@0: public static NumberViewer createNumberViewer( String l, int f, NumberSink dm) {
samer@0: return current.createNumberViewer(l,f,dm);
samer@0: }
samer@0:
samer@0: public static NumberViewer createNumberViewer( String l, int f) {
samer@0: return current.createNumberViewer(l,f,null);
samer@0: }
samer@0:
samer@0: // .......................................................
samer@0: private static boolean reg=true;
samer@0:
samer@0: /** If false, subsequent calls to registerViewable()
samer@0: are ignored */
samer@0: public static boolean setAutoRegister(boolean f) { boolean old=reg; reg=f; return old; }
samer@0: public static void registerAgent(Agent a) { current.registerAgent(a); }
samer@0: public static void deregisterAgent(Agent a) { current.deregisterAgent(a); }
samer@0: public static void registerViewable(Viewable v) { if (reg) current.registerViewable(v); }
samer@0: public static void deregisterViewable(Viewable v) { current.deregisterViewable(v); }
samer@0: public static void exposeCommands(Agent a) { current.exposeCommands(a); }
samer@0: public static void exit() { current.exit(); }
samer@0:
samer@0: // .......................................................
samer@0: // these two are for handling commands
samer@0:
samer@0: /** The interface for any kind of string interpreter */
samer@0: public interface Interpreter {
samer@0: /** Do something with no return value */
samer@0: void execute(Reader txt);
samer@0:
samer@0: /** Evaluate something and return a value
samer@0: (perhaps we should require with no side-effects?) */
samer@0: Object evaluate(Reader txt);
samer@0: }
samer@0:
samer@0: private static Interpreter interp=new Interpreter() {
samer@0: public void execute(Reader txt) { Shell.print("Sorry - don't know how"); }
samer@0: public Object evaluate(Reader txt) { throw new Error("no interpreter"); }
samer@0: };
samer@0:
samer@0:
samer@0: /** Set the current interpreter that is statically available */
samer@0: public static void setInterpreter(Interpreter i) { interp=i; }
samer@0:
samer@0: /** Use the current interepreter to interpret the given String */
samer@0: public static void interpret(String cmd) { interp.execute(new StringReader(cmd)); }
samer@0: /** Use the current interepreter to interpret commands from the Reader */
samer@0: public static void interpret(Reader in) { interp.execute(in); }
samer@0:
samer@0:
samer@0:
samer@0: // .......................................................
samer@0: // Environments
samer@0:
samer@0: private static Stack stack=new Stack(); // environment stack
samer@0: private static Environment _env=Environment.top(); // current environment
samer@0: private static Interface current=new DefaultShell(); // current shell
samer@0:
samer@0: /** Pops the top of the Environment stack. The one below
samer@0: becomes the new current environment. */
samer@0: public static void pop() { _env=(Environment)stack.pop(); }
samer@0:
samer@0: /** Push given Environment on top of stack. It becomes
samer@0: the new current environment. */
samer@0: public static void push(Environment e) { stack.push(_env); _env=e; }
samer@0:
samer@0: /** Pushes a new environment which contains no data but
samer@0: has the given base node. Used to establish a new node context */
samer@0: public static void push(Node n) { push(new Environment(_env,n)); }
samer@0:
samer@0: /** The same as push(new Node(nm))
ie, uses
samer@0: base node of current environment as a parent */
samer@0: public static void push(String nm) { push(new Environment(_env,nm)); }
samer@0:
samer@0: /** Return current node, the one at the top of the stack (without removing it) */
samer@0: public static Environment env() { return _env; }
samer@0:
samer@0: // -------------------------------------------------------
samer@0:
samer@0: /** Get a double value from the current environment. Name
samer@0: can be absolute or relative to current base node. Returns def
samer@0: if no matching value is found */
samer@0: public static double getDouble(String nm, double def) {
samer@0: return X._double(datum(nm),def);
samer@0: }
samer@0:
samer@0: /** See description for getDouble() */
samer@0: public static int getInt(String nm, int def) {
samer@0: return X._int(datum(nm),def);
samer@0: }
samer@0:
samer@0: /** See description for getDouble() */
samer@0: public static boolean getBoolean(String nm, boolean def) {
samer@0: return X._bool(datum(nm),def);
samer@0: }
samer@0:
samer@0: /** See description for getDouble() */
samer@0: public static String getString(String nm, String def) {
samer@0: return X.string(datum(nm),def);
samer@0: }
samer@0:
samer@0: /** Get a String from current environment, throwing an Exception
samer@0: if no value is found. */
samer@0: public static String getString(String nm) throws Exception {
samer@0: return X.string(datum(nm));
samer@0: }
samer@0:
samer@0: public static Color getColor(String nm, Color def) {
samer@0: return X.color(datum(nm),def);
samer@0: }
samer@0:
samer@0: /** Search for named Datum in current Environment. */
samer@0: public static Datum datum(String nm) { return _env.datum(nm); }
samer@0:
samer@0: /** Add and return new binding to current environment. */
samer@0: public static Binding put(String nm, Object o) { return _env.add(nm,o); }
samer@0:
samer@0: /** Search for and return object bound to given name. */
samer@0: public static Object get(String nm) throws Exception {
samer@0: return _env.binding(nm).get();
samer@0: }
samer@0:
samer@0: /** Search for and return object bound to given name. */
samer@0: public static Object get(String nm,Object def) {
samer@0: try { return _env.binding(nm).get();}
samer@0: catch (Exception ex) { return def; }
samer@0: }
samer@0:
samer@0: /** Remove named binding from current environment, ONLY if it
samer@0: is bound to the given object. */
samer@0: public static void remove(String nm, Object vl) {
samer@0: Binding v=_env.binding(nm);
samer@0: try { if (v.get()==vl) v.remove(); }
samer@0: catch (Exception ex) { Shell.trace("Shell.remove error: "+ex); }
samer@0: }
samer@0:
samer@0:
samer@0: public static void exposeCommands(final Object[] cmds)
samer@0: {
samer@0: // create a temporary Agent to manage the array of command names
samer@0: exposeCommands( new Agent() {
samer@0: public void getCommands(Agent.Registry r) {
samer@0: r.setTarget(null);
samer@0: for (int i=0; i
samer@0:
samer@0: */
samer@0:
samer@0: class DefaultShell implements Shell.Interface
samer@0: {
samer@0: private PrintWriter writer=null;
samer@0: private PrintWriter stdout=new PrintWriter(System.out,true); // with autoflush
samer@1: private PrintWriter stderr=new PrintWriter(System.err,true); // with autoflush
samer@0:
samer@0: // DefaultShell() { trace("creating DefaultShell"); }
samer@0:
samer@0: // Different types of message
samer@0: public void print(String string) { stdout.println(string); }
samer@0: public void status(String string) { stdout.println(string); }
samer@0: public void trace(String string) { stderr.println(string); }
samer@0:
samer@0: public PrintWriter getPrintWriter()
samer@0: {
samer@0: if (writer==null)
samer@0: writer = new PrintWriter( new OutputStreamWriter(System.out));
samer@0: return writer;
samer@0: };
samer@0:
samer@0: public Shell.Dialog getDialog(String title) { return null; }
samer@0: public Shell.Window getWindow(String title) { return null; }
samer@0: public Container createButtonsFor(Agent agent) { return null; }
samer@0: public Viewer createViewerPanel(Viewer vwr) { return null; }
samer@0: public Component createLabel(String nm) { return null; }
samer@0: public NumberViewer createNumberViewer( String l, int f, NumberSink s) { return null; }
samer@0:
samer@0: // registry
samer@0: public void registerAgent(Agent a) {}
samer@0: public void deregisterAgent(Agent a) {}
samer@0: public void registerViewable(Viewable v) {}
samer@0: public void deregisterViewable(Viewable v) {}
samer@0: public void exposeCommands(Agent agent) {}
samer@0: public void exit() { System.exit(0); }
samer@0: }