001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino JavaScript Debugger code, released
017: * November 21, 2000.
018: *
019: * The Initial Developer of the Original Code is
020: * See Beyond Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 2000
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Christopher Oliver
026: *
027: * Alternatively, the contents of this file may be used under the terms of
028: * the GNU General Public License Version 2 or later (the "GPL"), in which
029: * case the provisions of the GPL are applicable instead of those above. If
030: * you wish to allow use of your version of this file only under the terms of
031: * the GPL and not to allow others to use your version of this file under the
032: * MPL, indicate your decision by deleting the provisions above and replacing
033: * them with the notice and other provisions required by the GPL. If you do
034: * not delete the provisions above, a recipient may use your version of this
035: * file under either the MPL or the GPL.
036: *
037: * ***** END LICENSE BLOCK ***** */
038: package org.mozilla.javascript.tools.shell;
039:
040: import java.io.*;
041: import java.awt.*;
042: import java.awt.event.*;
043: import javax.swing.*;
044: import javax.swing.event.*;
045: import javax.swing.text.Document;
046: import javax.swing.text.Segment;
047:
048: class ConsoleWrite implements Runnable {
049: private ConsoleTextArea textArea;
050: private String str;
051:
052: public ConsoleWrite(ConsoleTextArea textArea, String str) {
053: this .textArea = textArea;
054: this .str = str;
055: }
056:
057: public void run() {
058: textArea.write(str);
059: }
060: }
061:
062: class ConsoleWriter extends java.io.OutputStream {
063:
064: private ConsoleTextArea textArea;
065: private StringBuffer buffer;
066:
067: public ConsoleWriter(ConsoleTextArea textArea) {
068: this .textArea = textArea;
069: buffer = new StringBuffer();
070: }
071:
072: public synchronized void write(int ch) {
073: buffer.append((char) ch);
074: if (ch == '\n') {
075: flushBuffer();
076: }
077: }
078:
079: public synchronized void write(char[] data, int off, int len) {
080: for (int i = off; i < len; i++) {
081: buffer.append(data[i]);
082: if (data[i] == '\n') {
083: flushBuffer();
084: }
085: }
086: }
087:
088: public synchronized void flush() {
089: if (buffer.length() > 0) {
090: flushBuffer();
091: }
092: }
093:
094: public void close() {
095: flush();
096: }
097:
098: private void flushBuffer() {
099: String str = buffer.toString();
100: buffer.setLength(0);
101: SwingUtilities.invokeLater(new ConsoleWrite(textArea, str));
102: }
103: }
104:
105: public class ConsoleTextArea extends JTextArea implements KeyListener,
106: DocumentListener {
107: static final long serialVersionUID = 8557083244830872961L;
108:
109: private ConsoleWriter console1;
110: private ConsoleWriter console2;
111: private PrintStream out;
112: private PrintStream err;
113: private PrintWriter inPipe;
114: private PipedInputStream in;
115: private java.util.Vector history;
116: private int historyIndex = -1;
117: private int outputMark = 0;
118:
119: public void select(int start, int end) {
120: requestFocus();
121: super .select(start, end);
122: }
123:
124: public ConsoleTextArea(String[] argv) {
125: super ();
126: history = new java.util.Vector();
127: console1 = new ConsoleWriter(this );
128: console2 = new ConsoleWriter(this );
129: out = new PrintStream(console1);
130: err = new PrintStream(console2);
131: PipedOutputStream outPipe = new PipedOutputStream();
132: inPipe = new PrintWriter(outPipe);
133: in = new PipedInputStream();
134: try {
135: outPipe.connect(in);
136: } catch (IOException exc) {
137: exc.printStackTrace();
138: }
139: getDocument().addDocumentListener(this );
140: addKeyListener(this );
141: setLineWrap(true);
142: setFont(new Font("Monospaced", 0, 12));
143: }
144:
145: synchronized void returnPressed() {
146: Document doc = getDocument();
147: int len = doc.getLength();
148: Segment segment = new Segment();
149: try {
150: doc.getText(outputMark, len - outputMark, segment);
151: } catch (javax.swing.text.BadLocationException ignored) {
152: ignored.printStackTrace();
153: }
154: if (segment.count > 0) {
155: history.addElement(segment.toString());
156: }
157: historyIndex = history.size();
158: inPipe.write(segment.array, segment.offset, segment.count);
159: append("\n");
160: outputMark = doc.getLength();
161: inPipe.write("\n");
162: inPipe.flush();
163: console1.flush();
164: }
165:
166: public void eval(String str) {
167: inPipe.write(str);
168: inPipe.write("\n");
169: inPipe.flush();
170: console1.flush();
171: }
172:
173: public void keyPressed(KeyEvent e) {
174: int code = e.getKeyCode();
175: if (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_LEFT) {
176: if (outputMark == getCaretPosition()) {
177: e.consume();
178: }
179: } else if (code == KeyEvent.VK_HOME) {
180: int caretPos = getCaretPosition();
181: if (caretPos == outputMark) {
182: e.consume();
183: } else if (caretPos > outputMark) {
184: if (!e.isControlDown()) {
185: if (e.isShiftDown()) {
186: moveCaretPosition(outputMark);
187: } else {
188: setCaretPosition(outputMark);
189: }
190: e.consume();
191: }
192: }
193: } else if (code == KeyEvent.VK_ENTER) {
194: returnPressed();
195: e.consume();
196: } else if (code == KeyEvent.VK_UP) {
197: historyIndex--;
198: if (historyIndex >= 0) {
199: if (historyIndex >= history.size()) {
200: historyIndex = history.size() - 1;
201: }
202: if (historyIndex >= 0) {
203: String str = (String) history
204: .elementAt(historyIndex);
205: int len = getDocument().getLength();
206: replaceRange(str, outputMark, len);
207: int caretPos = outputMark + str.length();
208: select(caretPos, caretPos);
209: } else {
210: historyIndex++;
211: }
212: } else {
213: historyIndex++;
214: }
215: e.consume();
216: } else if (code == KeyEvent.VK_DOWN) {
217: int caretPos = outputMark;
218: if (history.size() > 0) {
219: historyIndex++;
220: if (historyIndex < 0) {
221: historyIndex = 0;
222: }
223: int len = getDocument().getLength();
224: if (historyIndex < history.size()) {
225: String str = (String) history
226: .elementAt(historyIndex);
227: replaceRange(str, outputMark, len);
228: caretPos = outputMark + str.length();
229: } else {
230: historyIndex = history.size();
231: replaceRange("", outputMark, len);
232: }
233: }
234: select(caretPos, caretPos);
235: e.consume();
236: }
237: }
238:
239: public void keyTyped(KeyEvent e) {
240: int keyChar = e.getKeyChar();
241: if (keyChar == 0x8 /* KeyEvent.VK_BACK_SPACE */) {
242: if (outputMark == getCaretPosition()) {
243: e.consume();
244: }
245: } else if (getCaretPosition() < outputMark) {
246: setCaretPosition(outputMark);
247: }
248: }
249:
250: public synchronized void keyReleased(KeyEvent e) {
251: }
252:
253: public synchronized void write(String str) {
254: insert(str, outputMark);
255: int len = str.length();
256: outputMark += len;
257: select(outputMark, outputMark);
258: }
259:
260: public synchronized void insertUpdate(DocumentEvent e) {
261: int len = e.getLength();
262: int off = e.getOffset();
263: if (outputMark > off) {
264: outputMark += len;
265: }
266: }
267:
268: public synchronized void removeUpdate(DocumentEvent e) {
269: int len = e.getLength();
270: int off = e.getOffset();
271: if (outputMark > off) {
272: if (outputMark >= off + len) {
273: outputMark -= len;
274: } else {
275: outputMark = off;
276: }
277: }
278: }
279:
280: public synchronized void postUpdateUI() {
281: // this attempts to cleanup the damage done by updateComponentTreeUI
282: requestFocus();
283: setCaret(getCaret());
284: select(outputMark, outputMark);
285: }
286:
287: public synchronized void changedUpdate(DocumentEvent e) {
288: }
289:
290: public InputStream getIn() {
291: return in;
292: }
293:
294: public PrintStream getOut() {
295: return out;
296: }
297:
298: public PrintStream getErr() {
299: return err;
300: }
301:
302: }
|