Mercurial > hg > jslab
view src/samer/core_/Shell.java @ 0:bf79fb79ee13
Initial Mercurial check in.
author | samer |
---|---|
date | Tue, 17 Jan 2012 17:50:20 +0000 |
parents | |
children | 5df24c91468d |
line wrap: on
line source
/* * Shell.java * * Copyright (c) 2000, Samer Abdallah, King's College London. * All rights reserved. * * This software is provided AS IS and WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ package samer.core; import java.io.*; import java.awt.*; import java.awt.event.*; import java.util.*; import samer.core.Environment.Datum; import samer.core.Environment.Binding; import samer.core.Environment.Autocoder; /** This class provides a set of static methods for some useful services. The actual implementation is provided by some object that implements the Shell.Interface interface. */ public class Shell { /** All shells must implement this interface. It provides service that * are generally useful but can be implemented in different ways, such * as printing messages and getting usable windows. */ public interface Interface { // different types of message void print(String msg); void status(String msg); void trace(String msg); // factory methods PrintWriter getPrintWriter(); Window getWindow(String title); Dialog getDialog(String title); Container createButtonsFor(Agent agent); Viewer createViewerPanel(Viewer vwr); Component createLabel(String nm); NumberViewer createNumberViewer( String label, int flags, NumberSink s); // agents and viewables void registerViewable(Viewable v); void deregisterViewable(Viewable v); void registerAgent(Agent a); void deregisterAgent(Agent a); void exposeCommands(Agent agent); void exit(); } /** Interface returned by the getWindow method of the Shell.Interface interface. The window is not necessarily visible on return -- use the <code>expose()</code> method to make it so. NB: distinct from java.awt.Window. */ public interface Window { /** Make window visible */ void expose(); /** Hide and destroy window */ void dispose(); /** Should behave just like in <code>java.awt.Window</code> */ void addWindowListener(WindowListener wl); /** Returns the AWT container for this window, in to which components can be added in the normal way */ Container container(); } /** Interface returned by the getDialog method of the Shell.Interface interface. The dialog is not necessarily visible on return -- use the <code>expose()</code> method to make it so. <p>A dialog is distinct from a window in that it is modal, and is dismissed by one of a set of buttons. <p>NB: distinct from java.awt.Dialog */ public interface Dialog { /** Make dialog visible */ void expose(); /** Hide and destroy dialog */ void dispose(); /** Typically, the dialog will add a new button with the given label. */ void addAction(String cmd); /** Returns the text of the button used to dismiss the dialog */ String result(); /** Returns the AWT container for this window, in to which components can be added in the normal way */ Container container(); } // ....................................................... /** Sets the static current shell to point to the given shell */ public static void setShell(Interface sh) { current=sh; } public static void print(String msg) { current.print(msg); } public static void status(String msg) { current.status(msg); } public static void trace(String msg) { current.trace(msg); } public static PrintWriter getPrintWriter() { return current.getPrintWriter(); } public static Window getWindow(String title) { return current.getWindow(title); } public static Dialog getDialog(String title) { return current.getDialog(title); } /** Create and return a new Panel containing the given Viewer */ public static Viewer createViewerPanel(Viewer v ) { return current.createViewerPanel(v); } /** Return an AWT Container containing buttons for each the commands reported by the given Agent */ public static Container createButtonsFor(Agent a) { return current.createButtonsFor(a); } /** Return a label component. Can be AWT, Swing, or whatever */ public static Component createLabel(String txt) { return current.createLabel(txt); } public static NumberViewer createNumberViewer( String l, int f, NumberSink dm) { return current.createNumberViewer(l,f,dm); } public static NumberViewer createNumberViewer( String l, int f) { return current.createNumberViewer(l,f,null); } // ....................................................... private static boolean reg=true; /** If false, subsequent calls to <code>registerViewable()</code> are ignored */ public static boolean setAutoRegister(boolean f) { boolean old=reg; reg=f; return old; } public static void registerAgent(Agent a) { current.registerAgent(a); } public static void deregisterAgent(Agent a) { current.deregisterAgent(a); } public static void registerViewable(Viewable v) { if (reg) current.registerViewable(v); } public static void deregisterViewable(Viewable v) { current.deregisterViewable(v); } public static void exposeCommands(Agent a) { current.exposeCommands(a); } public static void exit() { current.exit(); } // ....................................................... // these two are for handling commands /** The interface for any kind of string interpreter */ public interface Interpreter { /** Do something with no return value */ void execute(Reader txt); /** Evaluate something and return a value (perhaps we should require with no side-effects?) */ Object evaluate(Reader txt); } private static Interpreter interp=new Interpreter() { public void execute(Reader txt) { Shell.print("Sorry - don't know how"); } public Object evaluate(Reader txt) { throw new Error("no interpreter"); } }; /** Set the current interpreter that is statically available */ public static void setInterpreter(Interpreter i) { interp=i; } /** Use the current interepreter to interpret the given String */ public static void interpret(String cmd) { interp.execute(new StringReader(cmd)); } /** Use the current interepreter to interpret commands from the Reader */ public static void interpret(Reader in) { interp.execute(in); } // ....................................................... // Environments private static Stack stack=new Stack(); // environment stack private static Environment _env=Environment.top(); // current environment private static Interface current=new DefaultShell(); // current shell /** Pops the top of the Environment stack. The one below becomes the new current environment. */ public static void pop() { _env=(Environment)stack.pop(); } /** Push given Environment on top of stack. It becomes the new current environment. */ public static void push(Environment e) { stack.push(_env); _env=e; } /** Pushes a new environment which contains no data but has the given base node. Used to establish a new node context */ public static void push(Node n) { push(new Environment(_env,n)); } /** The same as <code>push(new Node(nm)) </code> ie, uses base node of current environment as a parent */ public static void push(String nm) { push(new Environment(_env,nm)); } /** Return current node, the one at the top of the stack (without removing it) */ public static Environment env() { return _env; } // ------------------------------------------------------- /** Get a double value from the current environment. Name can be absolute or relative to current base node. Returns def if no matching value is found */ public static double getDouble(String nm, double def) { return X._double(datum(nm),def); } /** See description for getDouble() */ public static int getInt(String nm, int def) { return X._int(datum(nm),def); } /** See description for getDouble() */ public static boolean getBoolean(String nm, boolean def) { return X._bool(datum(nm),def); } /** See description for getDouble() */ public static String getString(String nm, String def) { return X.string(datum(nm),def); } /** Get a String from current environment, throwing an Exception if no value is found. */ public static String getString(String nm) throws Exception { return X.string(datum(nm)); } public static Color getColor(String nm, Color def) { return X.color(datum(nm),def); } /** Search for named Datum in current Environment. */ public static Datum datum(String nm) { return _env.datum(nm); } /** Add and return new binding to current environment. */ public static Binding put(String nm, Object o) { return _env.add(nm,o); } /** Search for and return object bound to given name. */ public static Object get(String nm) throws Exception { return _env.binding(nm).get(); } /** Search for and return object bound to given name. */ public static Object get(String nm,Object def) { try { return _env.binding(nm).get();} catch (Exception ex) { return def; } } /** Remove named binding from current environment, ONLY if it is bound to the given object. */ public static void remove(String nm, Object vl) { Binding v=_env.binding(nm); try { if (v.get()==vl) v.remove(); } catch (Exception ex) { Shell.trace("Shell.remove error: "+ex); } } public static void exposeCommands(final Object[] cmds) { // create a temporary Agent to manage the array of command names exposeCommands( new Agent() { public void getCommands(Agent.Registry r) { r.setTarget(null); for (int i=0; i<cmds.length; i++) r.add((String)cmds[i]); } public void execute(String cmd, Environment env) {} } ); } // ....................................................... // helper functions for creating windows and dialogs /** Creates and shows a dialog containing the given component and "ok" and "cancel" buttons. Returns "ok" or "cancel" depending on which button was pressed. */ public static String showDialogFor(Component comp, String name) { Dialog dlg = Shell.getDialog(name); dlg.container().add(comp); dlg.addAction("cancel"); dlg.addAction("ok"); dlg.expose(); dlg.dispose(); return dlg.result(); } /** Expose the given Viewer. Uses the Shell.getWindow() to get some screen space, and adds the Viewer's component into the Shell.Window's container. */ public static Window showViewer( Viewer vwr, String name) { return expose(vwr.getComponent(),name); } /** same as showViewer() */ public static Window expose( Viewer vwr, String name) { return expose(vwr.getComponent(),name); } /** Expose the given AWT Component. Uses the Shell.getWindow() to get some screen space, and adds the component into the Shell.Window's container. The window is given the supplied name. */ public static Window expose( Component c, String name) { Component [] cs = {c}; return expose(cs,name); } /** Expose a bunch of Components in one window with the given name. The layout is the default one determined by the current shell's implementation of getWindow(). */ public static Window expose( Component[] cs, String name) { Window win = Shell.getWindow(name); ViewerWindowListener l=new ViewerWindowListener(win,null); // vwr); //win.container().setLayout(new BoxLayout()); //win.container().setLayout(new BorderLayout()); // win.container().add(c,BorderLayout.CENTER); if (cs!=null) for (int i=0; i<cs.length; i++) win.container().add(cs[i]); win.container().addContainerListener(l); win.addWindowListener(l); win.expose(); return win; } /** Completely removes all trace of the given viewer. Works by calling its detach() method to relinquish any resources and drop references to itself, and removing it from its parent container if it has one. */ public static void releaseViewer(Viewer vwr) { vwr.detach(); Component c=vwr.getComponent(); Container p=c.getParent(); if (p!=null) p.remove(c); } /** A singleton WindowListener that, when attached to a Window, calls Shell.exit() when the window is closed. */ public static WindowListener exitListener() { return exitter; } private static WindowListener exitter = new WindowAdapter() { public void windowClosing(WindowEvent e) { Shell.exit(); } }; // Private listener class for handling a window containing a viewer public static WindowListener closeListener(Window w) { return new ViewerWindowListener(w,null); } private static class ViewerWindowListener extends WindowAdapter implements ContainerListener { Viewer vwr; Window win; public ViewerWindowListener(Window w, Viewer v) { win=w; vwr=v; } public void windowClosing(WindowEvent e) { if (vwr!=null) vwr.detach(); win.dispose(); } public void componentAdded(ContainerEvent e) {} public void componentRemoved(ContainerEvent e) { if (win.container().getComponentCount()>0) win.container().validate(); else EventQueue.invokeLater( new Runnable() { public void run() { win.dispose(); }}); } } } /** A fairly minimal implementation of Shell.Interface Much of the functionality is missing: <ul> <li>Implementations of print, status and trace go directly to System.out, System.out and System.err respectively, hence usually to stdout and stderr. <li> Window, dialog, button, label, Viewer creation functions all return null. <li> Register agent or viewable does nothing. <lI> exit() exits the JVM by calling System.exit() </ul> */ class DefaultShell implements Shell.Interface { private PrintWriter writer=null; private PrintWriter stdout=new PrintWriter(System.out,true); // with autoflush private PrintWriter stderr=new PrintWriter(System.err); // without autoflush // DefaultShell() { trace("creating DefaultShell"); } // Different types of message public void print(String string) { stdout.println(string); } public void status(String string) { stdout.println(string); } public void trace(String string) { stderr.println(string); } public PrintWriter getPrintWriter() { if (writer==null) writer = new PrintWriter( new OutputStreamWriter(System.out)); return writer; }; public Shell.Dialog getDialog(String title) { return null; } public Shell.Window getWindow(String title) { return null; } public Container createButtonsFor(Agent agent) { return null; } public Viewer createViewerPanel(Viewer vwr) { return null; } public Component createLabel(String nm) { return null; } public NumberViewer createNumberViewer( String l, int f, NumberSink s) { return null; } // registry public void registerAgent(Agent a) {} public void deregisterAgent(Agent a) {} public void registerViewable(Viewable v) {} public void deregisterViewable(Viewable v) {} public void exposeCommands(Agent agent) {} public void exit() { System.exit(0); } }