package org.ripple.power.ui.view;
import javax.swing.*;
import javax.swing.text.*;
import org.ripple.power.ui.graphics.LColor;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class JConsole extends JScrollPane {
/**
*
*/
private static final long serialVersionUID = 1L;
private final JLabel imageLabel = new JLabel();
private OutputStream fromConsoleStream;
private InputStream in;
private PrintStream out, err;
private AttributeSet attrOut, attrError;
private PipePump outPump, errPump;
public void setImageIcon(ImageIcon icon) {
clear();
imageLabel.setIcon(icon);
imageLabel.setVisible(true);
}
public void imageShow() {
imageLabel.setVisible(true);
}
public void imageHide() {
imageLabel.setVisible(false);
}
public void uiprint(String mes) {
if (attrOut != null) {
imageHide();
print(mes, attrOut);
}
}
private int commandPos = 0;
private List<String> commandHistory = new ArrayList<String>();
private int commandHistoryIndex = 0;
private String currentCommand;
private MyJTextPane text;
private JPopupMenu contextMenu;
private final static String CMD_CUT = "Cut";
private final static String CMD_CLEAR = "Clear";
private final static String CMD_COPY = "Copy";
private final static String CMD_PASTE = "Paste";
public JConsole() {
super();
setBackground(new Color(70, 70, 70));
setForeground(Color.WHITE);
setBorder(BorderFactory.createLineBorder(LColor.black));
text = new MyJTextPane();
text.setAutoscrolls(true);
final Font lFont = new Font("Monospaced", Font.PLAIN, 12);
text.setText("");
text.setFont(lFont);
text.setMargin(new Insets(1, 1, 1, 1));
text.addKeyListener(new MyKeyListener());
setViewportView(text);
int size = 128;
imageLabel.setForeground(LColor.white);
imageLabel.setBackground(LColor.white);
imageLabel.setBounds(RPJSonLog.WIDTH / 2 - size / 2, RPJSonLog.HEIGHT
/ 2 - size / 2 - 10, size, size);
imageLabel.setVisible(false);
text.setLayout(null);
text.add(imageLabel);
contextMenu = new JPopupMenu();
final ActionListener lActionListener = new MyActionListener();
contextMenu.add(new JMenuItem(CMD_CUT)).addActionListener(
lActionListener);
contextMenu.add(new JMenuItem(CMD_COPY)).addActionListener(
lActionListener);
contextMenu.add(new JMenuItem(CMD_PASTE)).addActionListener(
lActionListener);
contextMenu.add(new JMenuItem(CMD_CLEAR)).addActionListener(
lActionListener);
text.addMouseListener(new MyMouseListener());
MutableAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, Color.BLACK);
attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, Color.WHITE);
attrOut = attr;
attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, Color.RED);
StyleConstants.setItalic(attr, true);
StyleConstants.setBold(attr, true);
attrError = attr;
try {
fromConsoleStream = new PipedOutputStream();
in = new PipedInputStream((PipedOutputStream) fromConsoleStream);
final PipedOutputStream lOutPipe = new PipedOutputStream();
out = new PrintStream(lOutPipe);
final PipedOutputStream lErrPipe = new PipedOutputStream();
err = new PrintStream(lErrPipe);
} catch (IOException e) {
e.printStackTrace();
}
requestFocus();
}
public void setOutAttributes(AttributeSet aAttribs) {
attrOut = aAttribs;
if (outPump != null) {
outPump.setAttr(aAttribs);
}
}
public void setErrAttributes(AttributeSet aAttribs) {
attrError = aAttribs;
if (errPump != null) {
errPump.setAttr(aAttribs);
}
}
public InputStream getInputStream() {
return in;
}
/**
* Get the input reader containing the text the user enters in the console.
*
* @return A text reader from which the user commands can be read.
*/
public Reader getIn() {
return new InputStreamReader(in);
}
/**
* The output stream to the console.
*
* @return An output stream on which the application can write text to the
* console.
*/
public PrintStream getOut() {
return out;
}
/**
* The error stream to the console.
*
* @return An output stream on which the application can write text to the
* console.
*/
public PrintStream getErr() {
return err;
}
// Focus handling.
public void requestFocus() {
super.requestFocus();
text.requestFocus();
}
// Remember the start of the command line.
private void initCommandPos() {
commandPos = textLength();
}
// Append text to the end of the text already present in the
// text component.
private void appendConsoleText(String aContent) {
final int lTxtLen = textLength();
text.select(lTxtLen, lTxtLen);
text.replaceSelection(aContent);
}
// Replace part of the text in the text component.
private String replaceConsoleText(Object aContent, int aFrom, int aTo) {
final String aContentRepr = aContent.toString();
text.select(aFrom, aTo);
text.replaceSelection(aContentRepr);
return aContentRepr;
}
private void moveCaret() {
if (text.getCaretPosition() < commandPos) {
text.setCaretPosition(textLength());
}
text.repaint();
}
private void processCommand() {
String lCommandRepr = getCmd();
if (lCommandRepr.length() != 0)
commandHistory.add(lCommandRepr);
lCommandRepr = lCommandRepr + "\n";
appendConsoleText("\n");
commandHistoryIndex = 0;
acceptLine(lCommandRepr);
text.repaint();
}
private String getCmd() {
try {
return text.getText(commandPos, textLength() - commandPos);
} catch (BadLocationException e) {
return "";
}
}
// Command history manipulation, go to the previous command.
// Note that the index runs in reverse.
private void prevHistory() {
if (commandHistory.size() == 0)
return;
if (commandHistoryIndex == 0)
currentCommand = getCmd();
if (commandHistoryIndex < commandHistory.size()) {
commandHistoryIndex++;
showHistory();
}
}
// Command history manipulation, go to the next command.
// Note that the index runs in reverse.
private void nextHistory() {
if (commandHistoryIndex == 0)
return;
commandHistoryIndex--;
showHistory();
}
// Show the command from the command history, pointed to by the index.
// Note that the index runs in reverse.
private void showHistory() {
String lShowLine;
if (commandHistoryIndex == 0)
lShowLine = currentCommand;
else
lShowLine = commandHistory.get(commandHistory.size()
- commandHistoryIndex);
replaceConsoleText(lShowLine, commandPos, textLength());
text.setCaretPosition(textLength());
text.repaint();
}
/**
* The user of the component can write a command in the console as if the
* user typed the command himself. The application using the console can
* simnulate user actions in this way.
*
* @param aCommand
*/
public void setCommand(String aCommand) {
String lCommandRepr = aCommand;
if (lCommandRepr.length() != 0)
commandHistory.add(lCommandRepr);
lCommandRepr = lCommandRepr + "\n";
appendConsoleText(lCommandRepr);
commandHistoryIndex = 0;
acceptLine(lCommandRepr);
text.repaint();
}
// Put the text that the user typed into the pipe, so that
// interested console clients can read the stuff from the in stream.
private void acceptLine(String aLine) {
try {
fromConsoleStream.write(aLine.getBytes());
fromConsoleStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Clear the console.
*/
public void clear() {
imageHide();
text.setText("");
text.repaint();
}
/**
* Print output to the console. Note that this will not be interpreted as a
* command line. See the setCommand() method for this functionality.
*
* @param aContent
* Print it to the console.
*/
public void print(final Object aContent) {
invokeAndWait(new Runnable() {
public void run() {
appendConsoleText(String.valueOf(aContent));
initCommandPos();
text.setCaretPosition(commandPos);
}
});
}
/**
* Print error to the console. Note that this will not be interpreted as a
* command line. See the setCommand() method for this functionality.
*
* @param aContent
* Print it to the console.
*/
public void error(Object aContent) {
print(aContent, attrError);
}
/**
* Print output to the console. Note that this will not be interpreted as a
* command line. See the setCommand() method for this functionality.
*
* @param aContent
* The message to be written to the console.
* @param aAttribs
* The text attributes used for this message.
*/
public void print(final Object aContent, final AttributeSet aAttribs) {
invokeAndWait(new Runnable() {
public void run() {
appendConsoleText(String.valueOf(aContent));
initCommandPos();
text.setCaretPosition(commandPos);
}
});
}
public void setFont(Font aFont) {
super.setFont(aFont);
if (text != null)
text.setFont(aFont);
}
// Utility method to make sure a task is executed on the Swing display
// thread.
private void invokeAndWait(Runnable aRunnable) {
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(aRunnable);
} catch (Exception e) {
e.printStackTrace();
}
} else {
aRunnable.run();
}
}
private int textLength() {
return text.getDocument().getLength();
}
// The PipePump waits for input on an output stream, and copies the content
// to the console window.
// It is used to get the text from the pipes which are provided to the user
// of the console.
// It is the connection between the user streams and the console content.
private class PipePump implements Runnable {
private InputStream in;
private AttributeSet attr;
public void setAttr(AttributeSet aAttr) {
attr = aAttr;
}
public void run() {
try {
final byte[] lBuf = new byte[1024];
int lBytesRead;
while (in.read(lBuf, 0, 1) != -1) {
synchronized (JConsole.this) {
lBytesRead = in.read(lBuf, 1, 1023) + 1;
print(new String(lBuf, 0, lBytesRead), attr);
while (in.available() > 0) {
lBytesRead = in.read(lBuf);
print(new String(lBuf, 0, lBytesRead), attr);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class MyKeyListener implements KeyListener {
public void keyPressed(KeyEvent e) {
type(e);
}
public void keyTyped(KeyEvent e) {
type(e);
}
public void keyReleased(KeyEvent e) {
type(e);
}
private synchronized void type(KeyEvent e) {
switch (e.getKeyCode()) {
case (KeyEvent.VK_ENTER):
if (e.getID() == KeyEvent.KEY_PRESSED) {
processCommand();
initCommandPos();
text.setCaretPosition(commandPos);
}
e.consume();
text.repaint();
break;
case (KeyEvent.VK_UP):
if (e.getID() == KeyEvent.KEY_PRESSED)
prevHistory();
e.consume();
break;
case (KeyEvent.VK_DOWN):
if (e.getID() == KeyEvent.KEY_PRESSED)
nextHistory();
e.consume();
break;
case (KeyEvent.VK_LEFT):
case (KeyEvent.VK_BACK_SPACE):
case (KeyEvent.VK_DELETE):
if (text.getCaretPosition() <= commandPos)
e.consume();
break;
case (KeyEvent.VK_HOME):
text.setCaretPosition(commandPos);
e.consume();
break;
case (KeyEvent.VK_U):
if ((e.getModifiers() & InputEvent.CTRL_MASK) > 0) {
replaceConsoleText("", commandPos, textLength());
commandHistoryIndex = 0;
e.consume();
}
break;
case (KeyEvent.VK_ALT):
case (KeyEvent.VK_CAPS_LOCK):
case (KeyEvent.VK_CONTROL):
case (KeyEvent.VK_META):
case (KeyEvent.VK_SHIFT):
case (KeyEvent.VK_PRINTSCREEN):
case (KeyEvent.VK_SCROLL_LOCK):
case (KeyEvent.VK_PAUSE):
case (KeyEvent.VK_INSERT):
case (KeyEvent.VK_F1):
case (KeyEvent.VK_F2):
case (KeyEvent.VK_F3):
case (KeyEvent.VK_F4):
case (KeyEvent.VK_F5):
case (KeyEvent.VK_F6):
case (KeyEvent.VK_F7):
case (KeyEvent.VK_F8):
case (KeyEvent.VK_F9):
case (KeyEvent.VK_F10):
case (KeyEvent.VK_F11):
case (KeyEvent.VK_F12):
case (KeyEvent.VK_ESCAPE):
case (KeyEvent.VK_C):
break;
default:
if ((e.getModifiers() & (InputEvent.CTRL_MASK
| InputEvent.ALT_MASK | InputEvent.META_MASK)) == 0) {
moveCaret();
}
if ((e.paramString().contains("Backspace"))
&& (text.getCaretPosition() <= commandPos)) {
e.consume();
}
break;
}
}
}
private class MyMouseListener extends MouseAdapter {
public void mousePressed(MouseEvent aEvent) {
if (aEvent.isPopupTrigger())
contextMenu.show((Component) aEvent.getSource(), aEvent.getX(),
aEvent.getY());
}
public void mouseReleased(MouseEvent aEvent) {
if (aEvent.isPopupTrigger())
contextMenu.show((Component) aEvent.getSource(), aEvent.getX(),
aEvent.getY());
}
}
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent aEvent) {
final String lActionCommand = aEvent.getActionCommand();
if (lActionCommand.equals(CMD_CUT)) {
text.cut();
} else if (lActionCommand.equals(CMD_COPY)) {
text.copy();
} else if (lActionCommand.equals(CMD_PASTE)) {
text.paste();
} else if (lActionCommand.equals(CMD_CLEAR)) {
clear();
}
}
}
private class MyJTextPane extends RPTextArea {
/**
*
*/
private static final long serialVersionUID = 1L;
public MyJTextPane() {
super();
setCaretColor(Color.WHITE);
setBackground(new Color(0, 0, 0));
setForeground(Color.WHITE);
setLineWrap(true);
setColumns(20);
setRows(5);
}
public void cut() {
if (text.getCaretPosition() < commandPos)
super.copy();
else
super.cut();
}
public void paste() {
moveCaret();
super.paste();
}
}
}