/*
* IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
*
* http://izpack.org/
* http://izpack.codehaus.org/
*
* Copyright 2002 Jan Blok
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.text.Segment;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.Vector;
public final class Console
{
public static final int INITIAL_WIDTH = 800;
public static final int INITIAL_HEIGHT = 600;
public static void main(String[] args)
{
Runtime rt = Runtime.getRuntime();
Process p = null;
try
{
/*
* Start a new process in which to execute the commands in cmd, using the environment in
* env and use pwd as the current working directory.
*/
p = rt.exec(args);// , env, pwd);
new Console(p);
System.exit(p.exitValue());
}
catch (IOException e)
{
/*
* Couldn't even get the command to start. Most likely it couldn't be found because of a
* typo.
*/
System.out.println("Error starting: " + args[0]);
System.out.println(e);
}
}
private StdOut so;
private StdOut se;
public String getOutputData()
{
if (so != null)
{
return so.getData();
}
else
{
return "";
}
}
public String getErrorData()
{
if (se != null)
{
return se.getData();
}
else
{
return "";
}
}
public Console(Process p)
{
JFrame frame = new JFrame();
frame.setTitle("Console");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(screenSize.width / 2 - INITIAL_WIDTH / 2, screenSize.height / 2
- INITIAL_HEIGHT / 2);
ConsoleTextArea cta = new ConsoleTextArea();
JScrollPane scroll = new JScrollPane(cta);
scroll.setPreferredSize(new Dimension(INITIAL_WIDTH, INITIAL_HEIGHT));
frame.getContentPane().add(scroll);
frame.pack();
// From here down your shell should be pretty much
// as it is written here!
/*
* Start up StdOut, StdIn and StdErr threads that write the output generated by the process
* p to the screen, and feed the keyboard input into p.
*/
so = new StdOut(p, cta);
se = new StdOut(p, cta);
StdIn si = new StdIn(p, cta);
so.start();
se.start();
si.start();
// Wait for the process p to complete.
try
{
frame.setVisible(true);
p.waitFor();
}
catch (InterruptedException e)
{
/*
* Something bad happened while the command was executing.
*/
System.out.println("Error during execution");
System.out.println(e);
}
/*
* Now signal the StdOut, StdErr and StdIn threads that the process is done, and wait for
* them to complete.
*/
try
{
so.done();
se.done();
si.done();
so.join();
se.join();
si.join();
}
catch (InterruptedException e)
{
// Something bad happend to one of the Std threads.
System.out.println("Error in StdOut, StdErr or StdIn.");
System.out.println(e);
}
frame.setVisible(false);
}
}
class StdIn extends Thread
{
private BufferedReader kb;
private boolean processRunning;
private PrintWriter op;
public StdIn(Process p, ConsoleTextArea cta)
{
setDaemon(true);
InputStreamReader ir = new InputStreamReader(cta.getIn());
kb = new BufferedReader(ir);
BufferedOutputStream os = new BufferedOutputStream(p.getOutputStream());
op = new PrintWriter((new OutputStreamWriter(os)), true);
processRunning = true;
}
public void run()
{
try
{
while (kb.ready() || processRunning)
{
if (kb.ready())
{
op.println(kb.readLine());
}
}
}
catch (IOException e)
{
System.err.println("Problem reading standard input.");
System.err.println(e);
}
}
public void done()
{
processRunning = false;
}
}
class StdOut extends Thread
{
private InputStreamReader output;
private boolean processRunning;
private ConsoleTextArea cta;
private StringBuffer data;
public StdOut(Process p, ConsoleTextArea cta)
{
setDaemon(true);
output = new InputStreamReader(p.getInputStream());
this.cta = cta;
processRunning = true;
data = new StringBuffer();
}
public void run()
{
try
{
/*
* Loop as long as there is output from the process to be displayed or as long as the
* process is still running even if there is presently no output.
*/
while (output.ready() || processRunning)
{
// If there is output get it and display it.
if (output.ready())
{
char[] array = new char[255];
int num = output.read(array);
if (num != -1)
{
String s = new String(array, 0, num);
data.append(s);
SwingUtilities.invokeAndWait(new ConsoleWrite(cta, s));
}
}
}
}
catch (Exception e)
{
System.err.println("Problem writing to standard output.");
System.err.println(e);
}
}
public void done()
{
processRunning = false;
}
public String getData()
{
return data.toString();
}
}
class ConsoleWrite implements Runnable
{
private ConsoleTextArea textArea;
private String str;
public ConsoleWrite(ConsoleTextArea textArea, String str)
{
this.textArea = textArea;
this.str = str;
}
public void run()
{
textArea.write(str);
}
}
class ConsoleWriter extends java.io.OutputStream
{
private ConsoleTextArea textArea;
private StringBuffer buffer;
public ConsoleWriter(ConsoleTextArea textArea)
{
this.textArea = textArea;
buffer = new StringBuffer();
}
public synchronized void write(int ch)
{
buffer.append((char) ch);
if (ch == '\n')
{
flushBuffer();
}
}
public synchronized void write(char[] data, int off, int len)
{
for (int i = off; i < len; i++)
{
buffer.append(data[i]);
if (data[i] == '\n')
{
flushBuffer();
}
}
}
public synchronized void flush()
{
if (buffer.length() > 0)
{
flushBuffer();
}
}
public void close()
{
flush();
}
private void flushBuffer()
{
String str = buffer.toString();
buffer.setLength(0);
SwingUtilities.invokeLater(new ConsoleWrite(textArea, str));
}
}
class ConsoleTextArea extends JTextArea implements KeyListener, DocumentListener
{
/**
*
*/
private static final long serialVersionUID = 3258410625414475827L;
private ConsoleWriter console1;
private PrintStream out;
private PrintStream err;
private PrintWriter inPipe;
private PipedInputStream in;
private Vector<String> history;
private int historyIndex = -1;
private int outputMark = 0;
public void select(int start, int end)
{
requestFocus();
super.select(start, end);
}
public ConsoleTextArea()
{
super();
history = new java.util.Vector<String>();
console1 = new ConsoleWriter(this);
ConsoleWriter console2 = new ConsoleWriter(this);
out = new PrintStream(console1);
err = new PrintStream(console2);
PipedOutputStream outPipe = new PipedOutputStream();
inPipe = new PrintWriter(outPipe);
in = new PipedInputStream();
try
{
outPipe.connect(in);
}
catch (IOException exc)
{
exc.printStackTrace();
}
getDocument().addDocumentListener(this);
addKeyListener(this);
setLineWrap(true);
setFont(new Font("Monospaced", 0, 12));
}
void returnPressed()
{
Document doc = getDocument();
int len = doc.getLength();
Segment segment = new Segment();
try
{
synchronized (doc)
{
doc.getText(outputMark, len - outputMark, segment);
}
}
catch (javax.swing.text.BadLocationException ignored)
{
ignored.printStackTrace();
}
if (segment.count > 0)
{
history.addElement(segment.toString());
}
historyIndex = history.size();
inPipe.write(segment.array, segment.offset, segment.count);
append("\n");
synchronized (doc)
{
outputMark = doc.getLength();
}
inPipe.write("\n");
inPipe.flush();
console1.flush();
}
public void eval(String str)
{
inPipe.write(str);
inPipe.write("\n");
inPipe.flush();
console1.flush();
}
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_LEFT)
{
if (outputMark == getCaretPosition())
{
e.consume();
}
}
else if (code == KeyEvent.VK_HOME)
{
int caretPos = getCaretPosition();
if (caretPos == outputMark)
{
e.consume();
}
else if (caretPos > outputMark)
{
if (!e.isControlDown())
{
if (e.isShiftDown())
{
moveCaretPosition(outputMark);
}
else
{
setCaretPosition(outputMark);
}
e.consume();
}
}
}
else if (code == KeyEvent.VK_ENTER)
{
returnPressed();
e.consume();
}
else if (code == KeyEvent.VK_UP)
{
historyIndex--;
if (historyIndex >= 0)
{
if (historyIndex >= history.size())
{
historyIndex = history.size() - 1;
}
if (historyIndex >= 0)
{
String str = history.elementAt(historyIndex);
int len = getDocument().getLength();
replaceRange(str, outputMark, len);
int caretPos = outputMark + str.length();
select(caretPos, caretPos);
}
else
{
historyIndex++;
}
}
else
{
historyIndex++;
}
e.consume();
}
else if (code == KeyEvent.VK_DOWN)
{
int caretPos = outputMark;
if (history.size() > 0)
{
historyIndex++;
if (historyIndex < 0)
{
historyIndex = 0;
}
int len = getDocument().getLength();
if (historyIndex < history.size())
{
String str = history.elementAt(historyIndex);
replaceRange(str, outputMark, len);
caretPos = outputMark + str.length();
}
else
{
historyIndex = history.size();
replaceRange("", outputMark, len);
}
}
select(caretPos, caretPos);
e.consume();
}
}
public void keyTyped(KeyEvent e)
{
int keyChar = e.getKeyChar();
if (keyChar == 0x8 /* KeyEvent.VK_BACK_SPACE */)
{
if (outputMark == getCaretPosition())
{
e.consume();
}
}
else if (getCaretPosition() < outputMark)
{
setCaretPosition(outputMark);
}
}
public void keyReleased(KeyEvent e)
{
}
public synchronized void write(String str)
{
insert(str, outputMark);
int len = str.length();
outputMark += len;
select(outputMark, outputMark);
}
public synchronized void insertUpdate(DocumentEvent e)
{
int len = e.getLength();
int off = e.getOffset();
if (outputMark > off)
{
outputMark += len;
}
}
public synchronized void removeUpdate(DocumentEvent e)
{
int len = e.getLength();
int off = e.getOffset();
if (outputMark > off)
{
if (outputMark >= off + len)
{
outputMark -= len;
}
else
{
outputMark = off;
}
}
}
public void postUpdateUI()
{
// this attempts to cleanup the damage done by updateComponentTreeUI
requestFocus();
setCaret(getCaret());
synchronized (this)
{
select(outputMark, outputMark);
}
}
public void changedUpdate(DocumentEvent e)
{
}
public InputStream getIn()
{
return in;
}
public PrintStream getOut()
{
return out;
}
public PrintStream getErr()
{
return err;
}
}