/* Copyright 2012 Jan Ove Saltvedt This file is part of KBot. KBot is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. KBot 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 General Public License for more details. You should have received a copy of the GNU General Public License along with KBot. If not, see <http://www.gnu.org/licenses/>. */ package com.kbotpro.various; import java.io.*; import java.util.*; import javax.swing.*; public class TextAreaOutputStream extends OutputStream { // ***************************************************************************** // INSTANCE PROPERTIES // ***************************************************************************** private JTextArea textArea; // target text area private int maxLines; // maximum lines allowed in text area private LinkedList lineLengths; // length of lines within text area private int curLength; // length of current line private byte[] oneByte; // array for write(int val); // ***************************************************************************** // INSTANCE CONSTRUCTORS/INIT/CLOSE/FINALIZE // ***************************************************************************** public TextAreaOutputStream(JTextArea ta) { this(ta,1000); } public TextAreaOutputStream(JTextArea ta, int ml) { if(ml<1) { throw new IllegalArgumentException("Maximum lines of "+ml+" in TextAreaOutputStream constructor is not permitted"); } textArea=ta; maxLines=ml; lineLengths=new LinkedList(); curLength=0; oneByte=new byte[1]; } // ***************************************************************************** // INSTANCE METHODS - ACCESSORS // ***************************************************************************** public synchronized void clear() { lineLengths=new LinkedList(); curLength=0; textArea.setText(""); } /** Get the number of lines this TextArea will hold. */ public synchronized int getMaximumLines() { return maxLines; } /** Set the number of lines this TextArea will hold. */ public synchronized void setMaximumLines(int val) { maxLines=val; } // ***************************************************************************** // INSTANCE METHODS // ***************************************************************************** public void close() { if(textArea!=null) { textArea=null; lineLengths=null; oneByte=null; } } public void flush() { } public void write(int val) { oneByte[0]=(byte)val; write(oneByte,0,1); } public void write(byte[] ba) { write(ba,0,ba.length); } public synchronized void write(byte[] ba,int str,int len) { try { curLength+=len; if(bytesEndWith(ba,str,len,LINE_SEP)) { lineLengths.addLast(new Integer(curLength)); curLength=0; if(lineLengths.size()>maxLines) { textArea.replaceRange(null,0,((Integer)lineLengths.removeFirst()).intValue()); } } for(int xa=0; xa<10; xa++) { try { textArea.append(new String(ba,str,len)); break; } catch(Throwable thr) { // sometimes throws a java.lang.Error: Interrupted attempt to aquire write lock if(xa==9) { thr.printStackTrace(); } else { Thread.sleep(200); } } } } catch(Throwable thr) { CharArrayWriter caw=new CharArrayWriter(); thr.printStackTrace(new PrintWriter(caw,true)); textArea.append(System.getProperty("line.separator","\n")); textArea.append(caw.toString()); } } private boolean bytesEndWith(byte[] ba, int str, int len, byte[] ew) { if(len<LINE_SEP.length) { return false; } for(int xa=0,xb=(str+len-LINE_SEP.length); xa<LINE_SEP.length; xa++,xb++) { if(LINE_SEP[xa]!=ba[xb]) { return false; } } return true; } // ***************************************************************************** // STATIC PROPERTIES // ***************************************************************************** static private byte[] LINE_SEP=System.getProperty("line.separator","\n").getBytes(); } /* END PUBLIC CLASS */