001: package tcl.lang;
002:
003: // We can not compile outside of the tcl.lang package
004: // the perms inside jacl need to be fixed before this will work
005: //import tcl.lang.*;
006:
007: import java.awt.*;
008: import java.awt.event.*;
009:
010: import java.io.*;
011:
012: // we need to incluse swingempty.jar in CLASSPATH so we
013: // can compile with swing 1.0 and 1.1
014:
015: import com.sun.java.swing.*;
016: import com.sun.java.swing.text.*;
017: import com.sun.java.swing.event.*;
018:
019: import javax.swing.*;
020: import javax.swing.text.*;
021: import javax.swing.event.*;
022:
023: public class GuiShell {
024:
025: private static String pre_swing;
026:
027: static {
028: Class c = UIManager.class;
029: String c_name = c.getName();
030:
031: pre_swing = "com.sun.java.swing";
032: if (c_name.startsWith(pre_swing)) {
033: pre_swing = "javax.swing";
034: }
035:
036: }
037:
038: public GuiShell() {
039:
040: //init the platform defined look and feel if there is one
041:
042: try {
043: if (true || System.getProperty("os.name").equalsIgnoreCase(
044: "mac os")) {
045: UIManager.setLookAndFeel(pre_swing
046: + ".plaf.mac.MacLookAndFeel");
047: } else {
048: UIManager.setLookAndFeel(UIManager
049: .getSystemLookAndFeelClassName());
050: }
051: } catch (ClassNotFoundException e) {
052: } catch (UnsupportedLookAndFeelException e) {
053: } catch (IllegalAccessException e) {
054: } catch (InstantiationException e) {
055: }
056:
057: frame = new JFrame("Main");
058: frame.setSize(500, 350);
059: frame.setLocation(100, 100);
060: frame.addWindowListener(closer);
061:
062: edit = new Editor();
063:
064: edit.setEditable(true);
065:
066: edit.setFont(new Font("ariel", Font.PLAIN, 16));
067:
068: doc = edit.getDocument();
069:
070: append("% ");
071:
072: JScrollPane scroller = new JScrollPane(edit,
073: JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
074: JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
075:
076: frame.getContentPane().add("Center", scroller);
077:
078: frame.setVisible(true);
079: }
080:
081: public void setupInterp() {
082:
083: try {
084: interp.setVar("argv0", "tcl.lang.Shell", TCL.GLOBAL_ONLY);
085: interp.setVar("tcl_interactive", "1", TCL.GLOBAL_ONLY);
086:
087: interp.setVar("argv", TclList.newInstance(),
088: TCL.GLOBAL_ONLY);
089: interp.setVar("argc", "0", TCL.GLOBAL_ONLY);
090:
091: } catch (TclException e) {
092: throw new TclRuntimeError("unexpected TclException: " + e);
093: }
094:
095: ThreadedTclEventLoop tsr = new ThreadedTclEventLoop();
096: Thread t = new Thread(tsr);
097: t.setPriority(Thread.MIN_PRIORITY);
098: t.setDaemon(true);
099: t.start();
100:
101: }
102:
103: public class ThreadedTclEventLoop implements Runnable {
104:
105: public void run() {
106: Notifier notifier = interp.getNotifier();
107: while (true) {
108: Thread.yield();
109: Thread.yield();
110: notifier.doOneEvent(TCL.ALL_EVENTS);
111: }
112: }
113:
114: }
115:
116: public void setupStreamReaders() {
117:
118: try {
119: stdout = System.out;
120: stderr = System.err;
121: pin = new PipedInputStream();
122: pout = new PipedOutputStream(pin);
123: ps = new PrintStream(pout);
124: System.setOut(ps);
125: System.setErr(ps);
126: } catch (java.io.IOException e) {
127: e.printStackTrace(stderr);
128: }
129:
130: ThreadedStreamReader tsr = new ThreadedStreamReader();
131: Thread t = new Thread(tsr);
132: //t.setPriority(Thread.MIN_PRIORITY);
133: t.setDaemon(true);
134: t.start();
135:
136: }
137:
138: public class ThreadedStreamReader implements Runnable {
139:
140: public void run() {
141: BufferedReader br = new BufferedReader(
142: new InputStreamReader(pin));
143:
144: String nextline = null;
145:
146: while (true) {
147: try {
148: nextline = br.readLine() + "\n";
149: doc.insertString(doc.getLength(), nextline, null);
150: edit.setCaretPosition(doc.getLength());
151:
152: } catch (IOException e) {
153: e.printStackTrace(stderr);
154: } catch (BadLocationException e) {
155: e.printStackTrace(stderr);
156: }
157: }
158:
159: }
160:
161: }
162:
163: public static void main(String s[]) {
164: GuiShell gs = new GuiShell();
165:
166: gs.setupInterp(); //create thread for interp
167:
168: gs.setupStreamReaders(); //create thread for stream readers
169:
170: }
171:
172: public boolean isCommandComplete() {
173:
174: String cmd = cmd_buff.toString();
175:
176: //find out if it a complete Tcl command yet
177:
178: //System.out.println("cmd is \"" + cmd + "\"");
179:
180: return Interp.commandComplete(cmd);
181: }
182:
183: public void processCommand() {
184:
185: //System.out.println("now to process event");
186:
187: if (cmd_buff.length() == 0) {
188: return;
189: }
190:
191: ConsoleEvent evt = new ConsoleEvent();
192: interp.getNotifier().queueEvent(evt, TCL.QUEUE_TAIL);
193: evt.sync();
194:
195: if (evt.evalResult != null) {
196: String s = evt.evalResult.toString();
197: if (s.length() > 0) {
198: append(s);
199: append("\n");
200: }
201: } else {
202: TclException e = evt.evalException;
203: int code = e.getCompletionCode();
204: switch (code) {
205: case TCL.ERROR:
206: append(interp.getResult().toString());
207: append("\n");
208: break;
209: case TCL.BREAK:
210: append("invoked \"break\" outside of a loop\n");
211: break;
212: case TCL.CONTINUE:
213: append("invoked \"continue\" outside of a loop\n");
214: break;
215: default:
216: append("command returned bad code: " + code + "\n");
217: }
218: }
219:
220: //System.out.println("done processing event");
221:
222: //try to read any data still floating around in stdout or stderr
223:
224: System.out.flush();
225: System.err.flush();
226:
227: Thread.yield();
228: Thread.yield();
229:
230: }
231:
232: public class ConsoleEvent extends TclEvent {
233: TclObject evalResult;
234: TclException evalException;
235:
236: public ConsoleEvent() {
237: evalResult = null;
238: evalException = null;
239: }
240:
241: public int processEvent(int flags) {
242: try {
243: interp.eval(cmd_buff.toString(), 0);
244: evalResult = interp.getResult();
245: evalResult.preserve();
246: } catch (TclException e) {
247: evalException = e;
248: }
249:
250: return 1;
251: }
252: }
253:
254: //append this string into the text widget
255: public void append(String str) {
256:
257: try {
258: doc.insertString(doc.getLength(), str, null);
259: } catch (BadLocationException e) {
260: throw new RuntimeException(e.toString());
261: }
262:
263: }
264:
265: //delete char from the end of the widget
266: public void removeLastChar() {
267:
268: try {
269: doc.remove(doc.getLength() - 1, 1);
270: } catch (BadLocationException e) {
271: throw new RuntimeException(e.toString());
272: }
273:
274: }
275:
276: public class Editor extends JEditorPane {
277:
278: private final boolean debug = false;
279:
280: protected void processComponentKeyEvent(KeyEvent e) {
281:
282: if (debug) {
283: //System.out.println("processing " + e);
284: }
285:
286: if (e.getKeyCode() != 0) {
287: return; //only process key typed commands
288: }
289:
290: char c = e.getKeyChar();
291:
292: if (debug) {
293: System.out
294: .println("char is '" + c + "' = " + ((int) c));
295: }
296:
297: //if they pressed Return
298:
299: if (c == KeyEvent.VK_ENTER) {
300:
301: if (debug) {
302: System.out.println("added newline");
303: }
304:
305: cmd_buff.append("\n");
306: append("\n");
307:
308: if (isCommandComplete()) {
309:
310: processCommand();
311:
312: cmd_buff.setLength(0);
313:
314: append("% ");
315:
316: } else {
317:
318: append("> ");
319: }
320:
321: cur_line_chars = 0;
322:
323: }
324:
325: //if they pressed Delete or Backspace
326:
327: else if (c == KeyEvent.VK_BACK_SPACE
328: || c == KeyEvent.VK_DELETE) {
329:
330: //letter deleted
331:
332: if (debug) {
333: System.out.println("letter deleted");
334: }
335:
336: //stop deleting at front of this line
337:
338: if (cur_line_chars != 0) {
339: cmd_buff.setLength(cmd_buff.length() - 1);
340: cur_line_chars--;
341: removeLastChar();
342: } else {
343: if (debug) {
344: System.out.println("begin of cur_line");
345: }
346: }
347:
348: }
349:
350: else {
351: //for any other letter
352:
353: cmd_buff.append(c);
354: cur_line_chars++;
355: append(String.valueOf(c));
356:
357: }
358:
359: /*
360: if (debug) {
361: System.out.println("after event process");
362: System.out.println("cmd_buff is \"" + cmd_buff + "\"");
363: System.out.println("cmd_buff len is " + cmd_buff.length());
364: System.out.println("cur_line_chars is " + cur_line_chars);
365: }
366: */
367:
368: edit.setCaretPosition(doc.getLength());
369:
370: }
371:
372: }
373:
374: public static class WindowClosingHandler extends WindowAdapter {
375: public void windowClosing(WindowEvent e) {
376: System.exit(0);
377: }
378: }
379:
380: public static WindowListener closer = new WindowClosingHandler();
381:
382: private transient JFrame frame;
383: private transient Editor edit;
384: private transient Document doc;
385:
386: private transient PipedInputStream pin = null;
387: private transient PipedOutputStream pout = null;
388: private transient PrintStream ps = null;
389:
390: private transient PrintStream stdout = null;
391: private transient PrintStream stderr = null;
392: private transient Thread messageThread = null;
393:
394: private transient StringBuffer cmd_buff = new StringBuffer(200);
395: private transient int cur_line_chars = 0;
396: private transient int cmd_start_index = 0;
397:
398: private transient Interp interp = new Interp();
399:
400: }
|