package abstrasy.consoleui;
import abstrasy.Interpreter;
import abstrasy.Main;
import abstrasy.Node;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.SilentException;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
/**
* Abstrasy Interpreter
*
* Copyright : Copyright (c) 2006-2012, Luc Bruninx.
*
* Concédée sous licence EUPL, version 1.1 uniquement (la «Licence»).
*
* Vous ne pouvez utiliser la présente oeuvre que conformément à la Licence.
* Vous pouvez obtenir une copie de la Licence à l’adresse suivante:
*
* http://www.osor.eu/eupl
*
* Sauf obligation légale ou contractuelle écrite, le logiciel distribué sous
* la Licence est distribué "en l’état", SANS GARANTIES OU CONDITIONS QUELLES
* QU’ELLES SOIENT, expresses ou implicites.
*
* Consultez la Licence pour les autorisations et les restrictions
* linguistiques spécifiques relevant de la Licence.
*
*
* @author Luc Bruninx
* @version 1.0
*/
public class OutputTextArea extends JTextPane {
private OutputTextArea Me;
/*
* Sortie console (partiellement) compatible ANSI:
* ==============================================
*
* Le support des séquence d'échapement ANSI est actuellement partiel et uniquement en sortie.
* Les codes supportés sont les suivants:
*
* - \e[ (...) m où (...) peut être une liste de nombres sous forme de caractères séparés par des ';':
*
* 0 : Réinitialiser la sortie
*
* 1 : Bold on
* 3 : Italic on
* 4 : Underline on
*
* 22 : Bold off
* 23 : Italic off
* 24 : Underline off
*
* 30 : black (fg)
* 31 : red (fg)
* 32 : green (fg)
* 33 : yellow (fg)
* 34 : blue (fg)
* 35 : magenta (fg)
* 36 : cyan (fg)
* 37 : white (fg)
*
* 40 : black (bg)
* 41 : red (bg)
* 42 : green (bg)
* 43 : yellow (bg)
* 44 : blue (bg)
* 45 : magenta (bg)
* 46 : cyan (bg)
* 47 : white (bg)
*
* 38;5;n : Utilise la couleur n de la palette de 256 couleurs pour fg.
* 48;5;n : utilise la couleur n de la palette de 256 couleurs pour bg.
*
* - \e[nC : Insère n caractères d'espacement sans appliquer les styles.
*
* - \e]4;n;rgb:rr/gg/bb\e\\ : Enregistre les composentes rgb rr, gg et bb dans la palette de 256 couleurs à la position n.
* Noter que rr, gg et bb sont fournies en hexadécimal et sont compris dans [00..ff].
*
*/
private static final int MAXCOLORS = 256;
private Color[] colors = new Color[MAXCOLORS];
public static final Color COLOR_Reset_FG = Color.green;
public static final Color COLOR_Reset_BG = Color.black;
private Color currentFG = COLOR_Reset_FG;
private Color currentBG = COLOR_Reset_BG;
private boolean currentBOLD = false;
private boolean currentITALIC = false;
private boolean currentUNDERLINE = false;
public void resetStyles() {
currentFG = COLOR_Reset_FG;
currentBG = COLOR_Reset_BG;
currentBOLD = false;
currentITALIC = false;
currentUNDERLINE = false;
}
/**
* Convertir l'offset en numéro de ligne.
*
* @param offset >= 0
* @return numéro de la ligne >= 0
* @exception BadLocationException
*/
public int getLineOfOffset(int offset) throws BadLocationException {
Document doc = getDocument();
if (offset < 0) {
throw new BadLocationException("Can't translate offset to line", -1);
}
else if (offset > doc.getLength()) {
throw new BadLocationException("Can't translate offset to line", doc.getLength() + 1);
}
else {
Element map = getDocument().getDefaultRootElement();
return map.getElementIndex(offset);
}
}
/**
* Determine le nombre de lignes dans le document.
*
* @return NbrLignes > 0
*/
public int getLineCount() {
Element map = getDocument().getDefaultRootElement();
return map.getElementCount();
}
/**
* Determine l'offset du début de la ligne.
* Cette méthode est inspirée de la méthode du même nom dans JTextArea.
*
* @param line >= 0
* @return offset >= 0
* @exception BadLocationException
*/
public int getLineStartOffset(int line) throws BadLocationException {
int lineCount = getLineCount();
if (line < 0) {
throw new BadLocationException("Negative line", -1);
}
else if (line >= lineCount) {
throw new BadLocationException("No such line", getDocument().getLength() + 1);
}
else {
Element map = getDocument().getDefaultRootElement();
Element lineElem = map.getElement(line);
return lineElem.getStartOffset();
}
}
/**
* Determine l'offset de la fin de la ligne fournie en arguement.
* Cette méthode est inspirée de JTextArea.
*
* @param line >= 0
* @return offset >= 0
* @exception BadLocationException
*/
public int getLineEndOffset(int line) throws BadLocationException {
int lineCount = getLineCount();
if (line < 0) {
throw new BadLocationException("Negative line", -1);
}
else if (line >= lineCount) {
throw new BadLocationException("No such line", getDocument().getLength() + 1);
}
else {
Element map = getDocument().getDefaultRootElement();
Element lineElem = map.getElement(line);
int endOffset = lineElem.getEndOffset();
// hide the implicit break at the end of the document
return ((line == lineCount - 1) ? (endOffset - 1): endOffset);
}
}
public void append(String s) {
StyleContext sc = StyleContext.getDefaultStyleContext();
SimpleAttributeSet attributes = new SimpleAttributeSet();
attributes.addAttribute(StyleConstants.Foreground, currentFG);
//if(currentBG.getRGB()!=this.getBackground().getRGB()){
attributes.addAttribute(StyleConstants.Background, currentBG);
//}
attributes.addAttribute(StyleConstants.Bold, currentBOLD);
attributes.addAttribute(StyleConstants.Italic, currentITALIC);
attributes.addAttribute(StyleConstants.Underline, currentUNDERLINE);
int len = this.getDocument().getLength();
this.setCaretPosition(len); // placer le caret à la fin.
this.setSelectionStart(len);
this.setSelectionEnd(len);
setCharacterAttributes(attributes, false); // pas de style.
replaceSelection(s); // c'est un moyen pour insérer là où est le caret.
}
private String appendANSI_cache = "";
private int endOfANSI(String src, int deb) {
int i = deb;
if (i < src.length() && src.charAt(++i) == '[') {
/* séquence CSI */
String dico = "0123456789;";
while (i < src.length()) {
if (dico.indexOf(src.charAt(++i)) < 0) {
return i;
}
}
}
else if (i < src.length()) {
/* séquence non-CSI */
while (i < src.length()) {
if (src.charAt(++i) == '\\' && src.charAt(i - 1) == '\u001B') {
return i;
}
}
}
return -1;
}
public void appendANSI(String s) {
int aPos = 0;
int aIndex = 0;
int xIndex = 0;
String tmpString = "";
boolean stillSearching = true; // vrai tant qu'il y a des CSI à traiter...
String addString = appendANSI_cache + s;
appendANSI_cache = "";
if (addString.length() > 0) {
aIndex = addString.indexOf("\u001B");
if (aIndex == -1) { // pas de séquence, on termine...
append(addString);
return;
}
if (aIndex > 0) { // S'il y a des caractères avant la séquence...
tmpString = addString.substring(0, aIndex);
append(tmpString);
aPos = aIndex;
}
// A partir d'ici aPos est positionné sur le début de la séquence...
stillSearching = true;
while (stillSearching) {
xIndex = endOfANSI(addString, aPos); // on recherche la fin de la séquence...
if (xIndex >= 0) {
tmpString = addString.substring(aPos, xIndex + 1);
char lastChar = tmpString.charAt(tmpString.length() - 1);
if (lastChar == 'C') {
doANSI_Com(tmpString);
}
else if (lastChar == 'm') {
tmpString = addString.substring(aPos, xIndex + 1);
parseANSI_FG_Color(tmpString);
parseANSI_BG_Color(tmpString);
parseANSI_BOLD(tmpString);
parseANSI_ITALIC(tmpString);
parseANSI_UNDERLINE(tmpString);
}
else if (lastChar == '\\') {
/* non CSI sequence */
parseANSI_SelectRGB(tmpString);
}
aPos = xIndex + 1;
}
else { // the buffer ends halfway through the ansi string!
appendANSI_cache = addString.substring(aPos, addString.length());
stillSearching = false;
continue;
}
aIndex = addString.indexOf("\u001B", aPos);
if (aIndex == -1) { // S'il n'y a pas de séquence, on ajoute les caractères
tmpString = addString.substring(aPos, addString.length());
append(tmpString);
stillSearching = false;
continue; // puis au saute au début de la boucle suivante...
}
// S'il y a une autre séquence, on vide les caractères avant de procéder...
tmpString = addString.substring(aPos, aIndex);
aPos = aIndex;
append(tmpString);
}
}
}
private final static String spaces(int sc) {
String s = "";
for (int i = 0; i < sc; i++) {
s += " ";
}
return s;
}
public void doANSI_Com(String src) {
//System.out.println("*"+src+"*");
if (src.startsWith("\u001B[")) {
if (src.charAt(src.length() - 1) == 'C') {
try {
int nc = Integer.parseInt(src.substring(2, src.length() - 1));
Color tmpFG = currentFG;
Color tmpBG = currentBG;
boolean tmpB = currentBOLD;
boolean tmpI = currentITALIC;
boolean tmpU = currentUNDERLINE;
this.resetStyles();
append(spaces(nc));
currentFG = tmpFG;
currentBG = tmpBG;
currentBOLD = tmpB;
currentITALIC = tmpI;
currentUNDERLINE = tmpU;
}
catch (Exception e) {
// rien faire...
}
}
}
}
private Color getANSI_fg(String code, Color precedColor) {
//System.out.println(code);
if (code.equals("0")) {
return COLOR_Reset_FG;
}
else if (code.equals("30")) {
return Color.black;
}
else if (code.equals("31")) {
return Color.red;
}
else if (code.equals("32")) {
return Color.green;
}
else if (code.equals("33")) {
return Color.yellow;
}
else if (code.equals("34")) {
return Color.blue;
}
else if (code.equals("35")) {
return Color.magenta;
}
else if (code.equals("36")) {
return Color.cyan;
}
else if (code.equals("37")) {
return Color.white;
}
else {
return precedColor;
}
}
public void parseANSI_FG_Color(String src) {
Color fg = currentFG;
if (src.startsWith("\u001B[") && src.endsWith("m")) {
String[] decomp = (src.substring(2, src.length() - 1) + ";").split(";");
for (int i = 0; i < decomp.length; i++) {
if (decomp[i].equals("38") && ((i + 2) < decomp.length) && decomp[i + 1].equals("5")) {
/* 256 colors */
int ncolor = 0;
try {
ncolor = Integer.parseInt(decomp[i + 2]);
}
catch (Exception e) {
Interpreter.Log("ANSI CSI error: \\e" + src.substring(1) + " ...");
}
if (ncolor < 0 || ncolor >= MAXCOLORS) {
Interpreter.Log("ANSI CSI error: \\e" + src.substring(1) + " (the color number must be in [0.." + MAXCOLORS + "[) ...");
}
else {
fg = colors[ncolor];
}
i += 2;
i += 2;
}
else {
/* basic */
fg = getANSI_fg(decomp[i], fg);
}
}
}
currentFG = fg;
}
private Color getANSI_bg(String code, Color precedColor) {
//System.out.println(code);
if (code.equals("0")) {
return COLOR_Reset_BG;
}
else if (code.equals("40")) {
return Color.black;
}
else if (code.equals("41")) {
return Color.red;
}
else if (code.equals("42")) {
return Color.green;
}
else if (code.equals("43")) {
return Color.yellow;
}
else if (code.equals("44")) {
return Color.blue;
}
else if (code.equals("45")) {
return Color.magenta;
}
else if (code.equals("46")) {
return Color.cyan;
}
else if (code.equals("47")) {
return Color.white;
}
else {
return precedColor;
}
}
public void parseANSI_BG_Color(String src) {
Color bg = currentBG;
if (src.startsWith("\u001B[") && src.endsWith("m")) {
String[] decomp = (src.substring(2, src.length() - 1) + ";").split(";");
for (int i = 0; i < decomp.length; i++) {
if (decomp[i].equals("48") && ((i + 2) < decomp.length) && decomp[i + 1].equals("5")) {
/* 256 colors */
int ncolor = 0;
try {
ncolor = Integer.parseInt(decomp[i + 2]);
}
catch (Exception e) {
Interpreter.Log("ANSI CSI error: \\e" + src.substring(1) + " ...");
}
if (ncolor < 0 || ncolor >= MAXCOLORS) {
Interpreter.Log("ANSI CSI error: \\e" + src.substring(1) + " (the color number must be in [0.." + MAXCOLORS + "[) ...");
}
else {
bg = colors[ncolor];
}
i += 2;
}
else {
/* basic */
bg = getANSI_bg(decomp[i], bg);
}
}
}
currentBG = bg;
}
public void parseANSI_SelectRGB(String src) {
if (src.startsWith("\u001B]4;") && src.endsWith("\u001B\\")) {
String[] decomp = src.substring(4, src.length() - 2).split(";");
if (decomp.length == 2) {
// lire le numéro de couleur...
int ncolor = 0;
try {
ncolor = Integer.parseInt(decomp[0]);
}
catch (Exception e) {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ ...");
}
if (ncolor < 0 || ncolor >= MAXCOLORS) {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ (the color number must be in [0.." + MAXCOLORS + "[) ...");
}
else {
// numéro de couleur correct...
if (decomp[1].startsWith("rgb:")) {
decomp = decomp[1].substring(4).split("/");
if (decomp.length == 3) {
int r = 0;
int g = 0;
int b = 0;
try {
r = Integer.parseInt(decomp[0], 16);
g = Integer.parseInt(decomp[1], 16);
b = Integer.parseInt(decomp[2], 16);
}
catch (Exception e) {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ ...");
}
if (r < 0 || r > 255) {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ (red value must be in [0..255]) ...");
}
else if (g < 0 || g > 255) {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ (green value must be in [0..255]) ...");
}
else if (b < 0 || b > 255) {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ (blue value must be in [0..255]) ...");
}
else {
colors[ncolor] = new Color(r, g, b);
}
}
else {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ ...");
}
}
}
}
else {
Interpreter.Log("ANSI non-CSI sequence error: \\e]4;" + src.substring(4, src.length() - 2) + "\\e\\ ...");
}
}
}
public void parseANSI_BOLD(String src) {
boolean b = currentBOLD;
if (src.startsWith("\u001B[") && src.endsWith("m")) {
String[] decomp = (src.substring(2, src.length() - 1) + ";").split(";");
for (int i = 0; i < decomp.length; i++) {
if (decomp[i].equals("0")) {
b = false;
}
else if (decomp[i].equals("1")) {
b = true;
}
else if (decomp[i].equals("22")) {
b = false;
}
}
}
currentBOLD = b;
}
public void parseANSI_ITALIC(String src) {
boolean b = currentITALIC;
if (src.startsWith("\u001B[") && src.endsWith("m")) {
String[] decomp = (src.substring(2, src.length() - 1) + ";").split(";");
for (int i = 0; i < decomp.length; i++) {
if (decomp[i].equals("0")) {
b = false;
}
else if (decomp[i].equals("3")) {
b = true;
}
else if (decomp[i].equals("23")) {
b = false;
}
}
}
currentITALIC = b;
}
public void parseANSI_UNDERLINE(String src) {
boolean b = currentUNDERLINE;
if (src.startsWith("\u001B[") && src.endsWith("m")) {
String[] decomp = (src.substring(2, src.length() - 1) + ";").split(";");
for (int i = 0; i < decomp.length; i++) {
if (decomp[i].equals("0")) {
b = false;
}
else if (decomp[i].equals("4")) {
b = true;
}
else if (decomp[i].equals("24")) {
b = false;
}
}
}
currentUNDERLINE = b;
}
private transient Border border5;
private JPopupMenu jPopupMenu1 = new JPopupMenu();
private JMenuItem jMenuItem1 = new JMenuItem();
public OutputTextArea() {
super();
try {
Me = this;
initColors();
jbInit();
}
catch (Exception e) {
e.printStackTrace();
}
}
//Initialiser le composant
private void initColors() {
for (int i = 0; i < MAXCOLORS; i++) {
colors[i] = new Color(i, i, i);
}
}
public void setDocument(Document doc) {
if (doc instanceof DefaultStyledDocument)
super.setDocument(doc);
}
private static final String _getDefaultConsoleFontName_() {
Font[] fonts = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
//for(int i=0;i<fonts.length;i++)
// if(fonts[i].getFontName().toLowerCase().startsWith("dejavu sans mono"))
// return fonts[i].getFontName();
for(int i=0;i<fonts.length;i++)
if(fonts[i].getFontName().toLowerCase().startsWith("lucida sans typewriter regular"))
return fonts[i].getFontName();
return "Monospaced";
}
private void jbInit() throws Exception {
border5 = BorderFactory.createEmptyBorder(4, 4, 4, 4);
this.setOpaque(false);
this.setDocument(new DefaultStyledDocument());
this.setBackground(Color.black);
this.setFont(new Font(_getDefaultConsoleFontName_(), 0, 12));
this.setBorder(border5);
/**
* Eviter this.setEditable(false);
*
* Peut bloquer le processus!
*
**/
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
this_mouseClicked(e);
}
});
jPopupMenu1.setLabel("jPopupMenu1");
jMenuItem1.setText("Copy");
jMenuItem1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jMenuItem1_actionPerformed(e);
}
});
jPopupMenu1.add(jMenuItem1);
}
public void setBackground(Color color) {
super.setBackground(color);
this.setCaretColor(color);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
if (!Main.onOpenJDK) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
else {
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
g2.setPaint(this.getBackground());
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
super.paintComponent(g);
}
public int getCurrentCaret() {
int mcaret = -1;
try {
mcaret = this.getCaretPosition();
}
catch (Exception e) {
Interpreter.Log("OutpuTextArea:Catch Exception:");
e.printStackTrace();
}
return mcaret;
}
public void lockCaretPos() {
caretpos = getCurrentCaret();
//Interpreter.Log("caretLock:"+caretpos);
}
public void unlockCaretPos() {
//Interpreter.Log("UnLockCaret:"+caretpos);
caretpos = -1;
}
private int caretpos = -1;
private String readString = "";
public void processKeyEvent(KeyEvent e) {
// this is what one would expect to work but it doesn't because
// KEY_TYPED events never get here and they are the only ones
// that when consumed will successfully stop a non numeric
// character from being displayed in the text field.
char ckey = e.getKeyChar();
boolean isTyped = e.getID() == KeyEvent.KEY_TYPED;
int action = e.getKeyCode();
boolean isAction = e.isActionKey();
boolean ignoreKey = false;
if (caretpos < 0) {
e.consume();
return;
}
if (isAction) {
if (action == KeyEvent.VK_PAGE_UP) {
ignoreKey = true;
}
else if (action == KeyEvent.VK_PAGE_DOWN) {
ignoreKey = true;
}
else if (action == KeyEvent.VK_UP) {
ignoreKey = true;
}
else if (action == KeyEvent.VK_DOWN) {
ignoreKey = true;
}
else if (action == KeyEvent.VK_HOME) {
// if(e.getID()==KeyEvent.KEY_RELEASED){this.lockCaretPos();}
ignoreKey = true;
}
else if (action == KeyEvent.VK_END) {
ignoreKey = true;
}
else if (action == KeyEvent.VK_LEFT) {
if (caretpos >= 0 && this.getCaretPosition() <= caretpos) {
ignoreKey = true;
}
}
}
if (ckey == '\n' || ckey == '\r') {
if (caretpos >= 0 && isTyped) {
String readS = this.getText();
readS = readS.substring(readln_start_pos, readS.length());
readString = "";
for (int i = 0; i < readS.length(); i++) {
char c = readS.charAt(i);
if (c != '\n' && c != '\r') {
readString += c;
}
}
//Interpreter.Log("Saisie = \""+readString+"\"");
this.unlockCaretPos();
}
}
if (ignoreKey) {
e.consume();
}
else {
super.processKeyEvent(e);
}
}
public void processMouseEvent(MouseEvent e) {
if (caretpos != -1) {
e.consume();
}
else {
super.processMouseEvent(e);
}
}
public void processMouseMotionEvent(MouseEvent e) {
if (caretpos != -1) {
e.consume();
}
else {
super.processMouseMotionEvent(e);
}
}
//
private Object syncIO = new Object();
private Object waitIO = new Object();
private volatile boolean procIO = false;
private String _write_str_;
public void write(String str) throws Exception {
/**
* ATTENTION! ne doit pas être exécuté par le processus Swing!!!
*/
if (EventQueue.isDispatchThread())
throw new Error("Cannot call this method from the event dispatcher thread");
/*
* Un seul processus à la fois peut écrire à l'aide de write()...
*/
synchronized (syncIO) {
_write_str_ = str;
Runnable proc = new Runnable() {
public void run() {
try {
Me.appendANSI(_write_str_);
Me.setCaretPosition(Me.getDocument().getLength()); //this.getLineEndOffset(this.getLineCount() - 1));
}
catch (Exception e) {
if (Interpreter.isDebugMode()) {
e.printStackTrace();
}
if (e instanceof InterpreterException || e instanceof SilentException) {
//throw e;
e.printStackTrace();
}
}
//
SwingUtilities.invokeLater(new Runnable() {
public void run() {
procIO = false;
synchronized (waitIO) {
waitIO.notify();
}
}
});
//
}
};
procIO = true;
SwingUtilities.invokeLater(proc);
do {
synchronized (waitIO) {
waitIO.wait();
}
}
while (procIO);
}
}
public void clr() throws Exception {
clr("");
}
public void clr(String texte) throws Exception {
/**
* ATTENTION! ne doit pas être exécuté par le processus Swing!!!
*/
if (EventQueue.isDispatchThread())
throw new Error("Cannot call this method from the event dispatcher thread");
/*
* Un seul processus à la fois peut écrire à l'aide de write()...
*/
synchronized (syncIO) {
_write_str_ = texte;
Runnable proc = new Runnable() {
public void run() {
try {
Me.setText("");
Me.appendANSI(_write_str_);
Me.setCaretPosition(Me.getDocument().getLength()); //this.getLineEndOffset(this.getLineCount() - 1));
}
catch (Exception e) {
if (Interpreter.isDebugMode()) {
e.printStackTrace();
}
}
//
SwingUtilities.invokeLater(new Runnable() {
public void run() {
procIO = false;
synchronized (waitIO) {
waitIO.notify();
}
}
});
//
}
};
procIO = true;
SwingUtilities.invokeLater(proc);
do {
synchronized (waitIO) {
waitIO.wait();
}
}
while (procIO);
}
}
public String readln() throws Exception {
synchronized (syncIO) {
readString = "";
readln_start_pos = this.getText().length();
try {
this.setCaretPosition(this.getDocument().getLength());
}
catch (Exception e) {
Interpreter.Log("OutpuTextArea:Catch Exception:");
e.printStackTrace();
}
final OutputTextArea fout = this;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//fout.setEditable(true);
fout.setCaretColor(Color.lightGray);
fout.setFocusable(true);
fout.requestFocus();
fout.invalidate();
}
});
this.lockCaretPos();
while (caretpos >= 0) {
//try {
Thread.sleep(100);
//}
//catch (Exception e) {
// this.unlockCaretPos();
// throw e;
//}
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fout.setCaretColor(getBackground());
//fout.setEditable(false);
//fout.setFocusable(false);
}
});
}
return readString;
}
private int readln_start_pos = 0;
public String readln(Node startAt) throws Exception {
synchronized (syncIO) {
readString = "";
readln_start_pos = this.getText().length();
try {
this.setCaretPosition(this.getDocument().getLength());
}
catch (Exception e) {
Interpreter.Log("OutpuTextArea:Catch Exception:");
e.printStackTrace();
}
final OutputTextArea fout = this;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//fout.setEditable(true);
fout.setCaretColor(Color.lightGray);
fout.setFocusable(true);
fout.requestFocus();
fout.invalidate();
}
});
this.lockCaretPos();
while (caretpos >= 0) {
Interpreter myself = Interpreter.mySelf();
Interpreter.getSemaphore().sleep(100);
if (myself.isThreadRaising()) {
this.unlockCaretPos();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fout.setCaretColor(getBackground());
//fout.setEditable(false);
//fout.setFocusable(false);
}
});
Interpreter.mySelf().throwInterThreadException();
}
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fout.setCaretColor(getBackground());
//fout.setEditable(false);
//fout.setFocusable(false);
}
});
}
return readString;
}
private void this_mouseClicked(MouseEvent e) {
boolean isRightButton = (SwingUtilities.isRightMouseButton(e)) || (SwingUtilities.isLeftMouseButton(e) && e.isControlDown());
if (isRightButton) {
jMenuItem1.setEnabled(this.getSelectionStart() < this.getSelectionEnd());
jPopupMenu1.show(this, e.getX(), e.getY());
}
}
private void jMenuItem1_actionPerformed(ActionEvent e) {
this.copy();
}
public void setCurrentFG(Color colorCurrent) {
this.currentFG = colorCurrent;
}
public Color getCurrentFG() {
return currentFG;
}
public void setCurrentBG(Color currentBG) {
this.currentBG = currentBG;
}
public Color getCurrentBG() {
return currentBG;
}
public void setCurrentBOLD(boolean currentBOLD) {
this.currentBOLD = currentBOLD;
}
public boolean isCurrentBOLD() {
return currentBOLD;
}
public void setCurrentITALIC(boolean currentITALIC) {
this.currentITALIC = currentITALIC;
}
public boolean isCurrentITALIC() {
return currentITALIC;
}
public void setCurrentUNDERLINE(boolean currentUNDERLINE) {
this.currentUNDERLINE = currentUNDERLINE;
}
public boolean isCurrentUNDERLINE() {
return currentUNDERLINE;
}
}