/*
GNU GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This program 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
verion 2 of the License, or (at your option) any later version.
This program 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
/*
* Created on Jun 18, 2005
*/
package org.lobobrowser.gui;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.PlainDocument;
import javax.swing.text.Position;
/**
* The Swing document model that is used to store console output.
*/
public class ConsoleModel extends PlainDocument {
private static final long serialVersionUID = 1067196363975764005L;
private static final int MAX_LENGTH = 20000;
private static final Logger logger = Logger.getLogger(ConsoleModel.class.getName());
private final OutputStream outputStream;
/**
*
*/
public ConsoleModel() {
super();
this.outputStream = new LocalOutputStream();
}
private static ConsoleModel standard = new ConsoleModel();
public static ConsoleModel getStandard() {
return standard;
}
private void append(final byte[] bytes, final int offset, final int length) throws IOException {
try {
final String text = new String(bytes, offset, length, "ISO-8859-1");
final Position endPosition = getEndPosition();
insertString(endPosition.getOffset(), text, null);
final int overflow = getLength() - MAX_LENGTH;
if (overflow > 0) {
final Position startPosition = getStartPosition();
remove(startPosition.getOffset(), overflow);
}
} catch (final Exception err) {
// No standard I/O should be here!
logger.log(Level.SEVERE, "append()", err);
}
}
public PrintStream getPrintStream() {
return new PrintStream(this.outputStream);
}
private class LocalOutputStream extends OutputStream implements Runnable {
private final LinkedList<byte[]> dataQueue = new LinkedList<>();
public LocalOutputStream() {
final Thread t = new Thread(this, "ConsoleOutputStream");
t.setDaemon(true);
t.start();
}
/*
* (non-Javadoc)
*
* @see java.io.Flushable#flush()
*/
@Override
public void flush() throws IOException {
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#write(byte[])
*/
@Override
public void write(final byte[] b) throws IOException {
this.write(b, 0, b.length);
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#write(byte[], int, int)
*/
@Override
public void write(final byte[] b, final int off, final int len) throws IOException {
synchronized (this.dataQueue) {
byte[] actualBytes;
if ((off == 0) && (len == b.length)) {
actualBytes = b;
} else {
actualBytes = new byte[len];
System.arraycopy(b, off, actualBytes, 0, len);
}
this.dataQueue.add(actualBytes);
this.dataQueue.notify();
}
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#write(int)
*/
@Override
public void write(final int b) throws IOException {
this.write(new byte[] { (byte) b }, 0, 1);
}
public void run() {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
for (;;) {
try {
buffer.reset();
synchronized (this.dataQueue) {
while (this.dataQueue.size() == 0) {
this.dataQueue.wait();
}
final Iterator<byte[]> i = this.dataQueue.iterator();
while (i.hasNext()) {
final byte[] data = i.next();
buffer.write(data);
}
this.dataQueue.clear();
}
final byte[] allNewBytes = buffer.toByteArray();
append(allNewBytes, 0, allNewBytes.length);
// Sleep a little so document model is not
// constantly firing events.
Thread.sleep(300);
} catch (final Exception t) {
t.printStackTrace(System.err);
}
}
}
}
}