All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.grinder.util.FixedWidthFormatter Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2000 - 2011 Philip Aston
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package net.grinder.util;


/**
 * 

{@link MultiLineFormatter} for fixed width text cells.

* *

All white space is converted to plain spaces.

* *

When flow policy is {@code WORD_WRAP}, newlines in the * source are treated as preferred line breaks.

* * @author Philip Aston */ public final class FixedWidthFormatter extends AbstractMultiLineFormatter { /** * Alignment constants. */ public enum Align { /** Left alignment. */ LEFT { void pad(StringBuilder buffer, int remainder) { buffer.append(s_space, 0, remainder); } }, /** Centre alignment. */ CENTRE { void pad(StringBuilder buffer, int remainder) { final int charsLeft = (remainder + 1) / 2; final int charsRight = remainder / 2; buffer.insert(0, s_space, 0, charsLeft); buffer.append(s_space, 0, charsRight); } }, /** Right alignment. */ RIGHT { void pad(StringBuilder buffer, int remainder) { buffer.insert(0, s_space, 0, remainder); } }; abstract void pad(StringBuilder buffer, int space); /** Blank space to copy for padding. **/ private static final char[] s_space = new char[256]; static { for (int i = 0; i < s_space.length; i++) { s_space[i] = ' '; } } } /** * Flow constants. */ public enum Flow { /** The flow should be truncated. */ TRUNCATE { void flow(StringBuilder buffer, StringBuilder remainder, int width) { if (buffer.length() > width) { buffer.setLength(width); } } }, /** The flow should be wrapped. */ WRAP { void flow(StringBuilder buffer, StringBuilder remainder, int width) { if (buffer.length() > width) { // We prepend our remainder to the existing one. remainder.insert(0, buffer.substring(width)); // Truncate. buffer.setLength(width); } } }, /** The flow should be word-wrapped. */ WORD_WRAP { /** *

* Search to set splitPosition. Algorithm is first match from: *

    *
  1. First new line in first m_width + 1 characters (we replace all new * lines with splits)
  2. *
  3. Last white space in first m_width + 1 characters
  4. *
  5. The full width
  6. *
*

* *

* If the buffer is less than width wide, only new lines are taken into * account. *

* * @param buffer * The buffer. * @return Split position in range [0, m_width] */ private int findWordWrapSplitPosition(StringBuilder buffer, int width) { final int length = buffer.length(); final int right = Math.min(length, width); int splitPosition = 0; while (splitPosition < right) { if (buffer.charAt(splitPosition) == '\n') { return splitPosition; } ++splitPosition; } if (length > width) { splitPosition = width; do { if (Character.isWhitespace(buffer.charAt(splitPosition))) { return splitPosition; } } while (--splitPosition >= 0); return width; } else { return length; } } void flow(StringBuilder buffer, StringBuilder remainder, int width) { final int length = buffer.length(); final int splitPosition = findWordWrapSplitPosition(buffer, width); // Search forward to ignore white space until the first new // line, and set everything from there on as the remainder. int nextText = splitPosition; while (nextText < length) { final char c = buffer.charAt(nextText); if (!Character.isWhitespace(c)) { break; } ++nextText; if (c == '\n') { // If alignment is Align.LEFT, white space after the new // line will become leading space on the next line. break; } } if (nextText < length) { remainder.insert(0, buffer.substring(nextText)); } buffer.setLength(splitPosition); } }, /** The flow should overflow. */ OVERFLOW { void flow(StringBuilder buffer, StringBuilder remainder, int width) { } }; abstract void flow(StringBuilder buffer, StringBuilder remainder, int width); } private final Align m_alignment; private final Flow m_flow; private final int m_width; /** * Constructor. * * @param alignment * Alignment policy. One of { {@code ALIGN_LEFT}, {@code * ALIGN_CENTRE}, {@code ALIGN_RIGHT} } * @param flow * Flow policy. One of { {@code FLOW_TRUNCATE}, {@code FLOW_WRAP}, * {@code FLOW_WORD_WRAP}, {@code FLOW_OVERFLOW} } * @param width * The cell width. * */ public FixedWidthFormatter(Align alignment, Flow flow, int width) { if (width <= 0) { throw new IllegalArgumentException("Invalid width value"); } m_alignment = alignment; m_flow = flow; m_width = width; } /** * Alter buffer to contain a single line according to the policy of * the formatter. Insert remaining text at the start of * {@code remainder}. * * @param buffer Buffer to transform to a single line. * @param remainder Leftovers. */ public void transform(StringBuilder buffer, StringBuilder remainder) { m_flow.flow(buffer, remainder, m_width); final int length = buffer.length(); // Canonicalise white space. for (int k = 0; k < length; k++) { if (Character.isWhitespace(buffer.charAt(k))) { buffer.setCharAt(k, ' '); } } if (length < m_width) { // Buffer is less than width, pad. m_alignment.pad(buffer, m_width - length); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy