annotate src/samer/core_/Shell.java @ 8:5e3cbbf173aa tip

Reorganise some more
author samer
date Fri, 05 Apr 2019 22:41:58 +0100
parents 5df24c91468d
children
rev   line source
samer@0 1 /*
samer@0 2 * Shell.java
samer@0 3 *
samer@0 4 * Copyright (c) 2000, Samer Abdallah, King's College London.
samer@0 5 * All rights reserved.
samer@0 6 *
samer@0 7 * This software is provided AS IS and WITHOUT ANY WARRANTY;
samer@0 8 * without even the implied warranty of MERCHANTABILITY or
samer@0 9 * FITNESS FOR A PARTICULAR PURPOSE.
samer@0 10 */
samer@0 11
samer@0 12 package samer.core;
samer@0 13 import java.io.*;
samer@0 14 import java.awt.*;
samer@0 15 import java.awt.event.*;
samer@0 16 import java.util.*;
samer@0 17
samer@0 18 import samer.core.Environment.Datum;
samer@0 19 import samer.core.Environment.Binding;
samer@0 20 import samer.core.Environment.Autocoder;
samer@0 21
samer@0 22
samer@0 23
samer@0 24 /**
samer@0 25 This class provides a set of static methods for
samer@0 26 some useful services. The actual implementation is
samer@0 27 provided by some object that implements the
samer@0 28 Shell.Interface interface.
samer@0 29 */
samer@0 30
samer@0 31 public class Shell
samer@0 32 {
samer@0 33 /** All shells must implement this interface. It provides service that
samer@0 34 * are generally useful but can be implemented in different ways, such
samer@0 35 * as printing messages and getting usable windows. */
samer@0 36
samer@0 37 public interface Interface
samer@0 38 {
samer@0 39 // different types of message
samer@0 40 void print(String msg);
samer@0 41 void status(String msg);
samer@0 42 void trace(String msg);
samer@0 43
samer@0 44 // factory methods
samer@0 45 PrintWriter getPrintWriter();
samer@0 46 Window getWindow(String title);
samer@0 47 Dialog getDialog(String title);
samer@0 48
samer@0 49 Container createButtonsFor(Agent agent);
samer@0 50 Viewer createViewerPanel(Viewer vwr);
samer@0 51 Component createLabel(String nm);
samer@0 52
samer@0 53 NumberViewer createNumberViewer( String label, int flags, NumberSink s);
samer@0 54
samer@0 55 // agents and viewables
samer@0 56 void registerViewable(Viewable v);
samer@0 57 void deregisterViewable(Viewable v);
samer@0 58 void registerAgent(Agent a);
samer@0 59 void deregisterAgent(Agent a);
samer@0 60 void exposeCommands(Agent agent);
samer@0 61 void exit();
samer@0 62 }
samer@0 63
samer@0 64
samer@0 65 /**
samer@0 66 Interface returned by the getWindow method of the
samer@0 67 Shell.Interface interface. The window is not necessarily
samer@0 68 visible on return -- use the <code>expose()</code>
samer@0 69 method to make it so.
samer@0 70 NB: distinct from java.awt.Window.
samer@0 71 */
samer@0 72
samer@0 73 public interface Window {
samer@0 74 /** Make window visible */
samer@0 75 void expose();
samer@0 76
samer@0 77 /** Hide and destroy window */
samer@0 78 void dispose();
samer@0 79
samer@0 80 /** Should behave just like in <code>java.awt.Window</code> */
samer@0 81 void addWindowListener(WindowListener wl);
samer@0 82
samer@0 83 /** Returns the AWT container for this window, in to
samer@0 84 which components can be added in the normal way */
samer@0 85 Container container();
samer@0 86 }
samer@0 87
samer@0 88 /**
samer@0 89 Interface returned by the getDialog method of the
samer@0 90 Shell.Interface interface. The dialog is not necessarily
samer@0 91 visible on return -- use the <code>expose()</code>
samer@0 92 method to make it so.
samer@0 93 <p>A dialog is distinct from a window in that it
samer@0 94 is modal, and is dismissed by one of a set of buttons.
samer@0 95 <p>NB: distinct from java.awt.Dialog
samer@0 96 */
samer@0 97
samer@0 98 public interface Dialog {
samer@0 99 /** Make dialog visible */
samer@0 100 void expose();
samer@0 101
samer@0 102 /** Hide and destroy dialog */
samer@0 103 void dispose();
samer@0 104
samer@0 105 /** Typically, the dialog will add a new button with the
samer@0 106 given label. */
samer@0 107 void addAction(String cmd);
samer@0 108
samer@0 109 /** Returns the text of the button used to dismiss the dialog */
samer@0 110 String result();
samer@0 111
samer@0 112 /** Returns the AWT container for this window, in to
samer@0 113 which components can be added in the normal way */
samer@0 114 Container container();
samer@0 115 }
samer@0 116
samer@0 117
samer@0 118
samer@0 119 // .......................................................
samer@0 120
samer@0 121 /** Sets the static current shell to point to the given shell */
samer@0 122 public static void setShell(Interface sh) { current=sh; }
samer@0 123
samer@0 124 public static void print(String msg) { current.print(msg); }
samer@0 125 public static void status(String msg) { current.status(msg); }
samer@0 126 public static void trace(String msg) { current.trace(msg); }
samer@0 127
samer@0 128 public static PrintWriter getPrintWriter() { return current.getPrintWriter(); }
samer@0 129 public static Window getWindow(String title) { return current.getWindow(title); }
samer@0 130 public static Dialog getDialog(String title) { return current.getDialog(title); }
samer@0 131
samer@0 132 /** Create and return a new Panel containing the given Viewer */
samer@0 133 public static Viewer createViewerPanel(Viewer v ) {
samer@0 134 return current.createViewerPanel(v);
samer@0 135 }
samer@0 136
samer@0 137 /** Return an AWT Container containing buttons for each the
samer@0 138 commands reported by the given Agent */
samer@0 139 public static Container createButtonsFor(Agent a) {
samer@0 140 return current.createButtonsFor(a);
samer@0 141 }
samer@0 142
samer@0 143 /** Return a label component. Can be AWT, Swing, or whatever */
samer@0 144 public static Component createLabel(String txt) {
samer@0 145 return current.createLabel(txt);
samer@0 146 }
samer@0 147
samer@0 148 public static NumberViewer createNumberViewer( String l, int f, NumberSink dm) {
samer@0 149 return current.createNumberViewer(l,f,dm);
samer@0 150 }
samer@0 151
samer@0 152 public static NumberViewer createNumberViewer( String l, int f) {
samer@0 153 return current.createNumberViewer(l,f,null);
samer@0 154 }
samer@0 155
samer@0 156 // .......................................................
samer@0 157 private static boolean reg=true;
samer@0 158
samer@0 159 /** If false, subsequent calls to <code>registerViewable()</code>
samer@0 160 are ignored */
samer@0 161 public static boolean setAutoRegister(boolean f) { boolean old=reg; reg=f; return old; }
samer@0 162 public static void registerAgent(Agent a) { current.registerAgent(a); }
samer@0 163 public static void deregisterAgent(Agent a) { current.deregisterAgent(a); }
samer@0 164 public static void registerViewable(Viewable v) { if (reg) current.registerViewable(v); }
samer@0 165 public static void deregisterViewable(Viewable v) { current.deregisterViewable(v); }
samer@0 166 public static void exposeCommands(Agent a) { current.exposeCommands(a); }
samer@0 167 public static void exit() { current.exit(); }
samer@0 168
samer@0 169 // .......................................................
samer@0 170 // these two are for handling commands
samer@0 171
samer@0 172 /** The interface for any kind of string interpreter */
samer@0 173 public interface Interpreter {
samer@0 174 /** Do something with no return value */
samer@0 175 void execute(Reader txt);
samer@0 176
samer@0 177 /** Evaluate something and return a value
samer@0 178 (perhaps we should require with no side-effects?) */
samer@0 179 Object evaluate(Reader txt);
samer@0 180 }
samer@0 181
samer@0 182 private static Interpreter interp=new Interpreter() {
samer@0 183 public void execute(Reader txt) { Shell.print("Sorry - don't know how"); }
samer@0 184 public Object evaluate(Reader txt) { throw new Error("no interpreter"); }
samer@0 185 };
samer@0 186
samer@0 187
samer@0 188 /** Set the current interpreter that is statically available */
samer@0 189 public static void setInterpreter(Interpreter i) { interp=i; }
samer@0 190
samer@0 191 /** Use the current interepreter to interpret the given String */
samer@0 192 public static void interpret(String cmd) { interp.execute(new StringReader(cmd)); }
samer@0 193 /** Use the current interepreter to interpret commands from the Reader */
samer@0 194 public static void interpret(Reader in) { interp.execute(in); }
samer@0 195
samer@0 196
samer@0 197
samer@0 198 // .......................................................
samer@0 199 // Environments
samer@0 200
samer@0 201 private static Stack stack=new Stack(); // environment stack
samer@0 202 private static Environment _env=Environment.top(); // current environment
samer@0 203 private static Interface current=new DefaultShell(); // current shell
samer@0 204
samer@0 205 /** Pops the top of the Environment stack. The one below
samer@0 206 becomes the new current environment. */
samer@0 207 public static void pop() { _env=(Environment)stack.pop(); }
samer@0 208
samer@0 209 /** Push given Environment on top of stack. It becomes
samer@0 210 the new current environment. */
samer@0 211 public static void push(Environment e) { stack.push(_env); _env=e; }
samer@0 212
samer@0 213 /** Pushes a new environment which contains no data but
samer@0 214 has the given base node. Used to establish a new node context */
samer@0 215 public static void push(Node n) { push(new Environment(_env,n)); }
samer@0 216
samer@0 217 /** The same as <code>push(new Node(nm)) </code> ie, uses
samer@0 218 base node of current environment as a parent */
samer@0 219 public static void push(String nm) { push(new Environment(_env,nm)); }
samer@0 220
samer@0 221 /** Return current node, the one at the top of the stack (without removing it) */
samer@0 222 public static Environment env() { return _env; }
samer@0 223
samer@0 224 // -------------------------------------------------------
samer@0 225
samer@0 226 /** Get a double value from the current environment. Name
samer@0 227 can be absolute or relative to current base node. Returns def
samer@0 228 if no matching value is found */
samer@0 229 public static double getDouble(String nm, double def) {
samer@0 230 return X._double(datum(nm),def);
samer@0 231 }
samer@0 232
samer@0 233 /** See description for getDouble() */
samer@0 234 public static int getInt(String nm, int def) {
samer@0 235 return X._int(datum(nm),def);
samer@0 236 }
samer@0 237
samer@0 238 /** See description for getDouble() */
samer@0 239 public static boolean getBoolean(String nm, boolean def) {
samer@0 240 return X._bool(datum(nm),def);
samer@0 241 }
samer@0 242
samer@0 243 /** See description for getDouble() */
samer@0 244 public static String getString(String nm, String def) {
samer@0 245 return X.string(datum(nm),def);
samer@0 246 }
samer@0 247
samer@0 248 /** Get a String from current environment, throwing an Exception
samer@0 249 if no value is found. */
samer@0 250 public static String getString(String nm) throws Exception {
samer@0 251 return X.string(datum(nm));
samer@0 252 }
samer@0 253
samer@0 254 public static Color getColor(String nm, Color def) {
samer@0 255 return X.color(datum(nm),def);
samer@0 256 }
samer@0 257
samer@0 258 /** Search for named Datum in current Environment. */
samer@0 259 public static Datum datum(String nm) { return _env.datum(nm); }
samer@0 260
samer@0 261 /** Add and return new binding to current environment. */
samer@0 262 public static Binding put(String nm, Object o) { return _env.add(nm,o); }
samer@0 263
samer@0 264 /** Search for and return object bound to given name. */
samer@0 265 public static Object get(String nm) throws Exception {
samer@0 266 return _env.binding(nm).get();
samer@0 267 }
samer@0 268
samer@0 269 /** Search for and return object bound to given name. */
samer@0 270 public static Object get(String nm,Object def) {
samer@0 271 try { return _env.binding(nm).get();}
samer@0 272 catch (Exception ex) { return def; }
samer@0 273 }
samer@0 274
samer@0 275 /** Remove named binding from current environment, ONLY if it
samer@0 276 is bound to the given object. */
samer@0 277 public static void remove(String nm, Object vl) {
samer@0 278 Binding v=_env.binding(nm);
samer@0 279 try { if (v.get()==vl) v.remove(); }
samer@0 280 catch (Exception ex) { Shell.trace("Shell.remove error: "+ex); }
samer@0 281 }
samer@0 282
samer@0 283
samer@0 284 public static void exposeCommands(final Object[] cmds)
samer@0 285 {
samer@0 286 // create a temporary Agent to manage the array of command names
samer@0 287 exposeCommands( new Agent() {
samer@0 288 public void getCommands(Agent.Registry r) {
samer@0 289 r.setTarget(null);
samer@0 290 for (int i=0; i<cmds.length; i++) r.add((String)cmds[i]);
samer@0 291 }
samer@0 292 public void execute(String cmd, Environment env) {}
samer@0 293 } );
samer@0 294 }
samer@0 295
samer@0 296 // .......................................................
samer@0 297 // helper functions for creating windows and dialogs
samer@0 298
samer@0 299
samer@0 300 /** Creates and shows a dialog containing the given component
samer@0 301 and "ok" and "cancel" buttons. Returns "ok" or "cancel"
samer@0 302 depending on which button was pressed. */
samer@0 303
samer@0 304 public static String showDialogFor(Component comp, String name)
samer@0 305 {
samer@0 306 Dialog dlg = Shell.getDialog(name);
samer@0 307
samer@0 308 dlg.container().add(comp);
samer@0 309 dlg.addAction("cancel");
samer@0 310 dlg.addAction("ok");
samer@0 311 dlg.expose();
samer@0 312 dlg.dispose();
samer@0 313
samer@0 314 return dlg.result();
samer@0 315 }
samer@0 316
samer@0 317
samer@0 318
samer@0 319 /**
samer@0 320 Expose the given Viewer. Uses the Shell.getWindow() to get
samer@0 321 some screen space, and adds the Viewer's component into the
samer@0 322 Shell.Window's container.
samer@0 323 */
samer@0 324
samer@0 325 public static Window showViewer( Viewer vwr, String name) {
samer@0 326 return expose(vwr.getComponent(),name);
samer@0 327 }
samer@0 328
samer@0 329 /** same as showViewer() */
samer@0 330 public static Window expose( Viewer vwr, String name) {
samer@0 331 return expose(vwr.getComponent(),name);
samer@0 332 }
samer@0 333
samer@0 334
samer@0 335 /**
samer@0 336 Expose the given AWT Component. Uses the Shell.getWindow() to get
samer@0 337 some screen space, and adds the component into the
samer@0 338 Shell.Window's container. The window is given the supplied name.
samer@0 339 */
samer@0 340
samer@0 341 public static Window expose( Component c, String name) {
samer@0 342 Component [] cs = {c};
samer@0 343 return expose(cs,name);
samer@0 344 }
samer@0 345
samer@0 346 /**
samer@0 347 Expose a bunch of Components in one window with the given name.
samer@0 348 The layout is the default one determined by the current shell's implementation
samer@0 349 of getWindow().
samer@0 350 */
samer@0 351 public static Window expose( Component[] cs, String name)
samer@0 352 {
samer@0 353 Window win = Shell.getWindow(name);
samer@0 354 ViewerWindowListener l=new ViewerWindowListener(win,null); // vwr);
samer@0 355
samer@0 356 //win.container().setLayout(new BoxLayout());
samer@0 357 //win.container().setLayout(new BorderLayout());
samer@0 358 // win.container().add(c,BorderLayout.CENTER);
samer@0 359 if (cs!=null) for (int i=0; i<cs.length; i++) win.container().add(cs[i]);
samer@0 360 win.container().addContainerListener(l);
samer@0 361 win.addWindowListener(l);
samer@0 362 win.expose();
samer@0 363 return win;
samer@0 364 }
samer@0 365
samer@0 366
samer@0 367 /**
samer@0 368 Completely removes all trace of the given viewer. Works by calling
samer@0 369 its detach() method to relinquish any resources and drop
samer@0 370 references to itself, and removing it from its parent container
samer@0 371 if it has one.
samer@0 372 */
samer@0 373
samer@0 374 public static void releaseViewer(Viewer vwr)
samer@0 375 {
samer@0 376 vwr.detach();
samer@0 377 Component c=vwr.getComponent();
samer@0 378 Container p=c.getParent();
samer@0 379 if (p!=null) p.remove(c);
samer@0 380 }
samer@0 381
samer@0 382
samer@0 383
samer@0 384 /**
samer@0 385 A singleton WindowListener that, when attached to a Window, calls
samer@0 386 Shell.exit() when the window is closed.
samer@0 387 */
samer@0 388
samer@0 389 public static WindowListener exitListener() { return exitter; }
samer@0 390 private static WindowListener exitter = new WindowAdapter() {
samer@0 391 public void windowClosing(WindowEvent e) { Shell.exit(); }
samer@0 392 };
samer@0 393
samer@0 394
samer@0 395
samer@0 396 // Private listener class for handling a window containing a viewer
samer@0 397
samer@0 398 public static WindowListener closeListener(Window w) { return new ViewerWindowListener(w,null); }
samer@0 399 private static class ViewerWindowListener extends WindowAdapter implements ContainerListener
samer@0 400 {
samer@0 401 Viewer vwr;
samer@0 402 Window win;
samer@0 403 public ViewerWindowListener(Window w, Viewer v) { win=w; vwr=v; }
samer@0 404 public void windowClosing(WindowEvent e) { if (vwr!=null) vwr.detach(); win.dispose(); }
samer@0 405 public void componentAdded(ContainerEvent e) {}
samer@0 406 public void componentRemoved(ContainerEvent e) {
samer@0 407 if (win.container().getComponentCount()>0) win.container().validate();
samer@0 408 else EventQueue.invokeLater( new Runnable() { public void run() { win.dispose(); }});
samer@0 409 }
samer@0 410 }
samer@0 411 }
samer@0 412
samer@0 413
samer@0 414
samer@0 415
samer@0 416 /**
samer@0 417 A fairly minimal implementation of Shell.Interface
samer@0 418 Much of the functionality is missing:
samer@0 419 <ul>
samer@0 420 <li>Implementations of print, status
samer@0 421 and trace go directly to System.out, System.out and System.err respectively,
samer@0 422 hence usually to stdout and stderr.
samer@0 423
samer@0 424 <li> Window, dialog, button, label, Viewer creation functions all return null.
samer@0 425 <li> Register agent or viewable does nothing.
samer@0 426 <lI> exit() exits the JVM by calling System.exit()
samer@0 427 </ul>
samer@0 428 */
samer@0 429
samer@0 430 class DefaultShell implements Shell.Interface
samer@0 431 {
samer@0 432 private PrintWriter writer=null;
samer@0 433 private PrintWriter stdout=new PrintWriter(System.out,true); // with autoflush
samer@1 434 private PrintWriter stderr=new PrintWriter(System.err,true); // with autoflush
samer@0 435
samer@0 436 // DefaultShell() { trace("creating DefaultShell"); }
samer@0 437
samer@0 438 // Different types of message
samer@0 439 public void print(String string) { stdout.println(string); }
samer@0 440 public void status(String string) { stdout.println(string); }
samer@0 441 public void trace(String string) { stderr.println(string); }
samer@0 442
samer@0 443 public PrintWriter getPrintWriter()
samer@0 444 {
samer@0 445 if (writer==null)
samer@0 446 writer = new PrintWriter( new OutputStreamWriter(System.out));
samer@0 447 return writer;
samer@0 448 };
samer@0 449
samer@0 450 public Shell.Dialog getDialog(String title) { return null; }
samer@0 451 public Shell.Window getWindow(String title) { return null; }
samer@0 452 public Container createButtonsFor(Agent agent) { return null; }
samer@0 453 public Viewer createViewerPanel(Viewer vwr) { return null; }
samer@0 454 public Component createLabel(String nm) { return null; }
samer@0 455 public NumberViewer createNumberViewer( String l, int f, NumberSink s) { return null; }
samer@0 456
samer@0 457 // registry
samer@0 458 public void registerAgent(Agent a) {}
samer@0 459 public void deregisterAgent(Agent a) {}
samer@0 460 public void registerViewable(Viewable v) {}
samer@0 461 public void deregisterViewable(Viewable v) {}
samer@0 462 public void exposeCommands(Agent agent) {}
samer@0 463 public void exit() { System.exit(0); }
samer@0 464 }