001: package interact;
002:
003: import java.awt.event.ActionEvent;
004: import java.io.IOException;
005: import java.io.PipedReader;
006: import java.io.PipedWriter;
007: import java.io.Reader;
008: import java.io.Writer;
009: import javax.swing.AbstractAction;
010: import javax.swing.Action;
011: import javax.swing.JTextArea;
012: import javax.swing.JTextArea;
013: import javax.swing.KeyStroke;
014: import javax.swing.SwingUtilities;
015: import javax.swing.text.JTextComponent;
016: import javax.swing.text.Keymap;
017:
018: /**
019: <p>This is a TextArea that creates a Reader and Writer, that can
020: be used (via getReader(), getWriter()) to interact with a scripting
021: language.
022:
023: <p>What a user types into the bottom of the text area appears on
024: the Reader.
025:
026: <p>Output from the PipedWriter usually appears above where the user
027: is typing. The user can type one line ahead as output occurs.
028:
029: <p>With help from R@y Tomlinson.
030:
031: <p><em>Collaborators</em>
032: <ul>
033: <li> OutputDocument is the Document model used by this TextArea.
034: <li> IOTextAreaWriter is the Writer returned by getWriter().
035: </ul>
036:
037: **/
038: public class IOTextArea extends JTextArea {
039:
040: private IOTextArea area = this ; // Synonym for this.
041: private OutputDocument doc = new OutputDocument();
042: private PipedReader readEnd = null;
043: private PipedWriter writeEnd = null;
044: private Writer writer = null;
045:
046: public IOTextArea(int rows, int cols) {
047: super (rows, cols);
048: this .area.setDocument(doc);
049: this .updateKeymap();
050: }
051:
052: public synchronized void replaceSelection(String s) {
053: super .replaceSelection(s);
054: }
055:
056: public void write(char[] buf, int off, int len) throws IOException {
057: this .write(new String(buf, off, len));
058: }
059:
060: public void write(final String s) {
061: SwingUtilities.invokeLater(new Runnable() {
062: public void run() {
063: int outPos = doc.getOutputOffset();
064: int dot = area.getCaretPosition();
065: doc.insertOutput(s, null);
066: if (dot >= outPos)
067: area.setCaretPosition(dot + s.length());
068: }
069: });
070: }
071:
072: protected void updateKeymap() {
073: // KeyStroke key = KeyStroke.getKeyStroke('\n'); didn't work.
074: KeyStroke key = KeyStroke.getKeyStroke(
075: java.awt.event.KeyEvent.VK_ENTER, 0, false);
076: Action action = new AbstractAction() {
077: public void actionPerformed(ActionEvent e) {
078: ((IOTextArea) e.getSource()).handleNewline();
079: }
080: };
081: Keymap newKeymap = JTextComponent.addKeymap("IOTextAreaKeymap",
082: this .area.getKeymap());
083: newKeymap.addActionForKeyStroke(key, action);
084: this .area.setKeymap(newKeymap);
085: }
086:
087: /** has someone created a reader? **/
088:
089: protected void enableIO() {
090: if (this .readEnd == null) {
091: this .readEnd = new PipedReader();
092: this .writeEnd = new PipedWriter();
093: try {
094: readEnd.connect(writeEnd);
095: } catch (IOException e) {
096: e.printStackTrace();
097: }
098: }
099: }
100:
101: public Reader getReader() {
102: enableIO();
103: return this .readEnd;
104: }
105:
106: protected void handleNewline() {
107: enableIO();
108: SwingUtilities.invokeLater(new Runnable() {
109: public void run() {
110: area.setCaretPosition(doc.handleNewline(writeEnd, area
111: .getCaretPosition()));
112: }
113: });
114: }
115:
116: public Writer getWriter() {
117: enableIO();
118: if (this .writer != null)
119: return this .writer;
120: this .writer = new IOTextAreaWriter(this.area);
121: return this.writer;
122: }
123:
124: }
|