/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotools.io;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.Writer;
import org.geotools.util.Utilities;
/**
* A writer that put some spaces in front of every lines. The indentation is initially set
* to 0 spaces. Users must invoke {@link #setIndentation} in order to set a different value.
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux
*
* @since 2.4
*/
public class IndentedLineWriter extends FilterWriter {
/**
* A string with a length equals to the indentation.
*/
private String margin = "";
/**
* {@code true} if we are about to write a new line.
*/
private boolean newLine = true;
/**
* {@code true} if we are waiting for a '\n' character.
*/
private boolean waitLF;
/**
* Constructs a stream which will add spaces in front of each line.
*
* @param out The underlying stream to write to.
*/
public IndentedLineWriter(final Writer out) {
super(out);
}
/**
* Returns the current indentation.
*
* @return The current indentation.
*/
public int getIdentation() {
return margin.length();
}
/**
* Sets the indentation to the specified value.
*
* @param width The new indentation.
*/
public void setIndentation(final int width) {
synchronized (lock) {
margin = Utilities.spaces(width);
}
}
/**
* Invoked when a new line is begining. The default implementation writes the
* amount of spaces specified by the last call to {@link #setIndentation}.
*
* @throws IOException If an I/O error occurs
*/
protected void beginNewLine() throws IOException {
out.write(margin);
}
/**
* Writes the specified character.
*
* @throws IOException If an I/O error occurs.
*/
private void doWrite(final int c) throws IOException {
assert Thread.holdsLock(lock);
if (newLine && (c!='\n' || !waitLF)) {
beginNewLine();
}
out.write(c);
if ((newLine = (c=='\r' || c=='\n')) == true) {
waitLF = (c=='\r');
}
}
/**
* Writes a single character.
*
* @throws IOException If an I/O error occurs.
*/
@Override
public void write(final int c) throws IOException {
synchronized (lock) {
doWrite(c);
}
}
/**
* Writes a portion of an array of characters.
*
* @param buffer Buffer of characters to be written.
* @param offset Offset from which to start reading characters.
* @param length Number of characters to be written.
* @throws IOException If an I/O error occurs.
*/
@Override
public void write(final char[] buffer, int offset, final int length) throws IOException {
final int upper = offset + length;
synchronized (lock) {
check: while (offset < upper) {
if (newLine) {
doWrite(buffer[offset++]);
continue;
}
final int lower = offset;
do {
final char c = buffer[offset];
if (c=='\r' || c=='\n') {
out.write(buffer, lower, offset-lower);
doWrite(c);
offset++;
continue check;
}
} while (++offset < upper);
out.write(buffer, lower, offset-lower);
break;
}
}
}
/**
* Writes a portion of a string.
*
* @param string String to be written.
* @param offset Offset from which to start reading characters.
* @param length Number of characters to be written.
* @throws IOException If an I/O error occurs.
*/
@Override
public void write(final String string, int offset, final int length) throws IOException {
final int upper = offset + length;
synchronized (lock) {
check: while (offset < upper) {
if (newLine) {
doWrite(string.charAt(offset++));
continue;
}
final int lower = offset;
do {
final char c = string.charAt(offset);
if (c=='\r' || c=='\n') {
out.write(string, lower, offset-lower);
doWrite(c);
offset++;
continue check;
}
} while (++offset < upper);
out.write(string, lower, offset-lower);
break;
}
}
}
}