Mercurial > hg > jslab
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 } |