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; i0) win.container().validate(); samer@0: else EventQueue.invokeLater( new Runnable() { public void run() { win.dispose(); }}); samer@0: } samer@0: } samer@0: } samer@0: samer@0: samer@0: samer@0: samer@0: /** samer@0: A fairly minimal implementation of Shell.Interface samer@0: Much of the functionality is missing: 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: }