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