/* Copyright 2008, 2009, 2010 by the Oxford University Computing Laboratory This file is part of HermiT. HermiT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. HermiT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with HermiT. If not, see <http://www.gnu.org/licenses/>. */ package org.semanticweb.HermiT.debugger; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.io.IOException; import java.io.Reader; import java.io.Writer; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; @SuppressWarnings("serial") public class ConsoleTextArea extends JTextArea { protected final ConsoleWriter m_writer; protected final ConsoleReader m_reader; protected int m_userTypedTextStart; public ConsoleTextArea() { setDocument(new ConsoleDocument()); m_writer=new ConsoleWriter(); m_reader=new ConsoleReader(); enableEvents(KeyEvent.KEY_EVENT_MASK); } public Writer getWriter() { return m_writer; } public Reader getReader() { return m_reader; } public void clear() { m_userTypedTextStart=0; setText(""); } protected void moveToEndIfNecessary() { int selectionStart=getSelectionStart(); int selectionEnd=getSelectionEnd(); if (selectionEnd<m_userTypedTextStart || (selectionEnd==m_userTypedTextStart && selectionStart!=selectionEnd)) { int length=getDocument().getLength(); select(length,length); } } public void replaceSelection(String string) { moveToEndIfNecessary(); super.replaceSelection(string); } protected void processKeyEvent(KeyEvent event) { if (event.getKeyCode()!=KeyEvent.VK_ENTER) super.processKeyEvent(event); if (event.getID()==KeyEvent.KEY_PRESSED && event.getKeyCode()==KeyEvent.VK_ENTER) { int textEnd=getDocument().getLength(); select(textEnd,textEnd); super.replaceSelection("\n"); textEnd=getDocument().getLength(); String text; try { text=getDocument().getText(m_userTypedTextStart,textEnd-m_userTypedTextStart); } catch (BadLocationException error) { text=""; } m_reader.addToBuffer(text); m_userTypedTextStart=textEnd; select(m_userTypedTextStart,m_userTypedTextStart); } } protected class ConsoleDocument extends PlainDocument { public void remove(int offset,int length) throws BadLocationException { if (offset>=m_userTypedTextStart) super.remove(offset,length); } public void insertString(int offset,String string,AttributeSet attributeSet) throws BadLocationException { if (offset>=m_userTypedTextStart) super.insertString(offset,string,attributeSet); } } protected class ConsoleWriter extends Writer implements ActionListener { protected final char[] m_buffer; protected final Timer m_timer; protected int m_firstFreeChar; public ConsoleWriter() { m_buffer=new char[4096]; m_timer=new Timer(500,this); m_timer.setRepeats(false); m_firstFreeChar=0; } public void close() { flush(); } public void flush() { synchronized (lock) { if (m_firstFreeChar>0) { final String string=new String(m_buffer,0,m_firstFreeChar); m_firstFreeChar=0; SwingUtilities.invokeLater(new Runnable() { public void run() { replaceSelection(string); m_userTypedTextStart=getDocument().getLength(); select(m_userTypedTextStart,m_userTypedTextStart); } }); m_timer.stop(); } } } public void write(char[] buffer,int offset,int count) { synchronized (lock) { int lastPosition=offset+count; while (offset!=lastPosition) { int toCopy=Math.min(m_buffer.length-m_firstFreeChar,count); if (toCopy!=0) { System.arraycopy(buffer,offset,m_buffer,m_firstFreeChar,toCopy); count-=toCopy; offset+=toCopy; boolean bufferWasEmpty=(m_firstFreeChar==0); m_firstFreeChar+=toCopy; if (m_firstFreeChar>=m_buffer.length) flush(); else if (bufferWasEmpty) m_timer.start(); } } } } public void actionPerformed(ActionEvent e) { flush(); } } protected class ConsoleReader extends Reader { protected char[] m_buffer; protected int m_nextCharToRead; protected int m_firstFreeChar; public ConsoleReader() { m_buffer=new char[4096]; m_nextCharToRead=0; m_firstFreeChar=0; } public void addToBuffer(String string) { synchronized (lock) { if (m_nextCharToRead==m_firstFreeChar) { m_nextCharToRead=0; m_firstFreeChar=0; } else { if (m_nextCharToRead!=0) { System.arraycopy(m_buffer,m_nextCharToRead,m_buffer,0,m_firstFreeChar-m_nextCharToRead); m_nextCharToRead=0; m_firstFreeChar=0; } } if (m_firstFreeChar+string.length()>m_buffer.length) { char[] newBuffer=new char[m_firstFreeChar+string.length()]; System.arraycopy(m_buffer,0,newBuffer,0,m_buffer.length); m_buffer=newBuffer; } string.getChars(0,string.length(),m_buffer,m_firstFreeChar); m_firstFreeChar+=string.length(); notifyAll(); } } public void close() throws IOException { } public int read(char[] buffer,int offset,int length) throws IOException { m_writer.flush(); synchronized (lock) { while (m_nextCharToRead==m_firstFreeChar) try { lock.wait(); } catch (InterruptedException error) { throw new IOException("Read interruipted."); } int toCopy=Math.min(m_firstFreeChar-m_nextCharToRead,length); System.arraycopy(m_buffer,m_nextCharToRead,buffer,offset,toCopy); m_nextCharToRead+=toCopy; return toCopy; } } } }