001: package interact;
002:
003: import java.awt.Container;
004: import java.awt.Font;
005: import java.awt.Toolkit;
006: import java.awt.event.WindowAdapter;
007: import java.awt.event.WindowEvent;
008: import java.io.PrintWriter;
009: import java.io.Reader;
010: import javax.swing.JFrame;
011: import javax.swing.JPanel;
012: import javax.swing.JScrollPane;
013: import jscheme.JScheme;
014: import jsint.InputPort;
015: import jsint.Procedure;
016: import jsint.Scheme;
017: import jsint.U;
018:
019: /**
020: An Interactor provides a window for interacting with a Jscheme
021: listener that is useful for debugging Java applications. A user
022: can provide an Interactor with name value pairs that are bound as
023: Jscheme global variables for easy reference.
024:
025: <p>Currently there can be only one Interactor at a time. If a
026: second one is started, because of global io variables, The old
027: window will become useless.
028: **/
029: public class Interactor implements Runnable {
030:
031: JFrame frame;
032: private IOTextArea area;
033:
034: private IOTextArea getArea() {
035: if (this .area == null) {
036: this .area = new IOTextArea(rows, cols);
037: this .area.setFont(new Font("monospaced", Font.PLAIN, 12));
038: }
039: return this .area;
040: }
041:
042: private Reader in;
043:
044: private Reader getReader() {
045: if (in == null)
046: this .in = this .getArea().getReader();
047: return this .in;
048: }
049:
050: private PrintWriter out;
051:
052: private PrintWriter getWriter() {
053: if (out == null)
054: out = new PrintWriter(getArea().getWriter());
055: return this .out;
056: }
057:
058: String name;
059: int rows;
060: int cols;
061: Object[] pairs;
062: String[] files;
063: JScheme js;
064:
065: /**
066: Start a new interactor in a new thread with Object, it, bound
067: to the Jscheme global <tt>it</tt>.
068: **/
069: public Interactor(Object it) {
070: this (it, new JScheme());
071: }
072:
073: /**
074: Start a new interactor in a new thread with Object, it, bound
075: to the Jscheme global <tt>it</tt>.
076: **/
077: public Interactor(Object it, JScheme js) {
078: this (new Object[] { "it", it }, js);
079: }
080:
081: /**
082: Start a new interactor in a new thread with the Object[], Pairs,
083: providing String "name", Object value pairs that
084: become Jscheme global bindings.
085: **/
086: public Interactor(Object[] pairs, JScheme js) {
087: this (true, "Interactor", pairs, 24, 80, null, js);
088: }
089:
090: /** Most general Interactor constructor.
091: @param newThread Start Interactor in a new thread?
092: @param name Name of JFrame.
093: @param pairs Name value pairs bound to Jscheme global variables.
094: @param rows Number of rows.
095: @param cols Number of columns.
096: @param files Additional arguments as in jsint.Scheme.main().
097: **/
098: public Interactor(final boolean newThread, final String name,
099: final Object[] pairs, final int rows, final int cols,
100: final String[] files, final JScheme js) {
101: this .name = name;
102: this .pairs = pairs;
103: this .rows = rows;
104: this .cols = cols;
105: this .files = files;
106: this .frame = createFrame();
107: this .js = js;
108: if (newThread)
109: new Thread(this ).start();
110: else
111: this .run();
112: }
113:
114: private JFrame createFrame() {
115: JFrame frame = new JFrame(name);
116: frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
117: frame.addWindowListener(new WindowAdapter() {
118: public void windowClosing(WindowEvent e) {
119: // KRA 11OCT99: It would be nice if we could stop Scheme too.
120: // But the user must do it.
121: // e.getWindow().dispose();
122: Toolkit.getDefaultToolkit().beep();
123: Interactor.this .getWriter().println(
124: "Type (exit) to exit this Frame!");
125: }
126: });
127: Container pane = frame.getContentPane();
128: JScrollPane scroll = new JScrollPane(this .getArea());
129: pane.add(scroll, "Center");
130: frame.pack();
131: frame.setVisible(true);
132: return frame;
133: }
134:
135: public void readEvalWriteLoop(String prompt) {
136: Scheme.readEvalWriteLoop(prompt);
137: }
138:
139: public void run() {
140: // These should be dynamic variables!
141: Scheme.pushEvaluator((jsint.Evaluator) js.getEvaluator());
142: jsint.BacktraceException.printJavaTrace = true;
143: jsint.Evaluator e = Scheme.currentEvaluator();
144: e.setInput(new InputPort(this .getReader()));
145: e.setOutput(this .getWriter());
146: e.setError(this .getWriter());
147: js.evalOrLoad("elf/basic.scm"); // Load some useful behavior.
148: this .importVariables();
149:
150: if (files != null)
151: this .loadFiles(files);
152: readEvalWriteLoop("> ");
153: this .frame.dispose();
154: this .frame = null;
155: Scheme.popEvaluator();
156: }
157:
158: private void loadFiles(String[] args) {
159: for (int i = 0; i < ((args == null) ? 0 : args.length); i++)
160: js.evalOrLoad(args[i]);
161: }
162:
163: /** Import variable value pairs. Import the class of the value just
164: to be safe. Show the bindings so the user can use them. **/
165: private void importVariables() {
166: Procedure importer = ((Procedure) js.getGlobalValue("import"));
167: if (pairs != null) {
168: js.call("display", "Bindings:\n");
169: for (int i = 0; i < pairs.length; i = i + 2)
170: importVariable(((String) pairs[i]), pairs[i + 1]);
171: }
172: }
173:
174: private void importVariable(String var, Object val) {
175: js.setGlobalValue(var, val);
176: js.call("import", val.getClass().getName());
177: js.call("display", var + " = " + U.stringify(val) + "\n",
178: Scheme.currentEvaluator().getOutput());
179: }
180:
181: /**
182: Run the interactor.
183:
184: **/
185: public static void main(String[] args) {
186: new Interactor(false, "Interactor", new Object[] { "now",
187: new java.util.Date() }, 24, 80, args, new JScheme());
188: System.out.println("Interaction done!");
189: System.exit(0);
190: }
191: }
|