mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
25.33.2012 263d085885df024dca9250cc03c807912b0a7662
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MultiColumnPrinter.java
@@ -6,17 +6,16 @@
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
@@ -27,13 +26,9 @@
package com.forgerock.opendj.ldap.tools;
import java.util.Enumeration;
import java.util.Vector;
/**
 * Utility class for printing aligned columns of text.
 * <P>
@@ -124,424 +119,351 @@
 *      John   Doe    john@foo.com  456-7890
 * </PRE>
 */
final class MultiColumnPrinter
{
final class MultiColumnPrinter {
  final public static int LEFT = 0;
    final public static int LEFT = 0;
  final public static int CENTER = 1;
    final public static int CENTER = 1;
  final public static int RIGHT = 2;
    final public static int RIGHT = 2;
  private int numCol = 2;
    private int numCol = 2;
  private int gap = 4;
    private int gap = 4;
  private int align = CENTER;
    private int align = CENTER;
  private int titleAlign = CENTER;
    private int titleAlign = CENTER;
  private String border = null;
    private String border = null;
  private Vector<String[]> titleTable = null;
    private Vector<String[]> titleTable = null;
  private Vector<int[]> titleSpanTable = null;
    private Vector<int[]> titleSpanTable = null;
  private final int curLength[];
    private final int[] curLength;
  private final ConsoleApplication app;
    private final ConsoleApplication app;
  /**
   * Creates a sorted new MultiColumnPrinter class using LEFT alignment and with
   * no title border.
   *
   * @param numCol
   *          number of columns
   * @param gap
   *          gap between each column
   */
  MultiColumnPrinter(final int numCol, final int gap,
      final ConsoleApplication app)
  {
    this(numCol, gap, null, LEFT, app);
  }
  /**
   * Creates a sorted new MultiColumnPrinter class using LEFT alignment.
   *
   * @param numCol
   *          number of columns
   * @param gap
   *          gap between each column
   * @param border
   *          character used to frame the titles
   */
  MultiColumnPrinter(final int numCol, final int gap, final String border,
      final ConsoleApplication app)
  {
    this(numCol, gap, border, LEFT, app);
  }
  /**
   * Creates a new MultiColumnPrinter class.
   *
   * @param numCol
   *          number of columns
   * @param gap
   *          gap between each column
   * @param border
   *          character used to frame the titles
   * @param align
   *          type of alignment within columns
   */
  MultiColumnPrinter(final int numCol, final int gap, final String border,
      final int align, final ConsoleApplication app)
  {
    titleTable = new Vector<String[]>();
    titleSpanTable = new Vector<int[]>();
    curLength = new int[numCol];
    this.numCol = numCol;
    this.gap = gap;
    this.border = border;
    this.align = align;
    this.titleAlign = LEFT;
    this.app = app;
  }
  /**
   * Adds to the row of strings to be used as the title for the table.
   *
   * @param row
   *          Array of strings to print in one row of title.
   */
  void addTitle(final String[] row)
  {
    if (row == null)
    {
      return;
    /**
     * Creates a sorted new MultiColumnPrinter class using LEFT alignment and
     * with no title border.
     *
     * @param numCol
     *            number of columns
     * @param gap
     *            gap between each column
     */
    MultiColumnPrinter(final int numCol, final int gap, final ConsoleApplication app) {
        this(numCol, gap, null, LEFT, app);
    }
    final int[] span = new int[row.length];
    for (int i = 0; i < row.length; i++)
    {
      span[i] = 1;
    /**
     * Creates a sorted new MultiColumnPrinter class using LEFT alignment.
     *
     * @param numCol
     *            number of columns
     * @param gap
     *            gap between each column
     * @param border
     *            character used to frame the titles
     */
    MultiColumnPrinter(final int numCol, final int gap, final String border,
            final ConsoleApplication app) {
        this(numCol, gap, border, LEFT, app);
    }
    addTitle(row, span);
  }
    /**
     * Creates a new MultiColumnPrinter class.
     *
     * @param numCol
     *            number of columns
     * @param gap
     *            gap between each column
     * @param border
     *            character used to frame the titles
     * @param align
     *            type of alignment within columns
     */
    MultiColumnPrinter(final int numCol, final int gap, final String border, final int align,
            final ConsoleApplication app) {
        titleTable = new Vector<String[]>();
        titleSpanTable = new Vector<int[]>();
        curLength = new int[numCol];
        this.numCol = numCol;
        this.gap = gap;
        this.border = border;
        this.align = align;
        this.titleAlign = LEFT;
  /**
   * Adds to the row of strings to be used as the title for the table. Also
   * allows for certain title strings to span multiple collumns The span
   * parameter is an array of integers which indicate how many collumns the
   * corresponding title string will occupy. For a row that is 4 collumns wide,
   * it is possible to have some title strings in a row to 'span' multiple
   * collumns:
   * <P>
   *
   * <PRE>
   * ------------------------------------
   *     Name             Contact
   * First  Last      Email       Phone
   * ------------------------------------
   * Bob    Jones  bob@foo.com   123-4567
   * John   Doe    john@foo.com  456-7890
   * </PRE>
   *
   * In the example above, the title row has a string 'Name' that spans 2
   * collumns. The string 'Contact' also spans 2 collumns. The above is done by
   * passing in to addTitle() an array that contains:
   *
   * <PRE>
   * span[0] = 2; // spans 2 collumns
   * span[1] = 0; // spans 0 collumns, ignore
   * span[2] = 2; // spans 2 collumns
   * span[3] = 0; // spans 0 collumns, ignore
   * </PRE>
   * <P>
   * A span value of 1 is the default. The method addTitle(String[] row)
   * basically does:
   *
   * <PRE>
   * int[] span = new int[row.length];
   * for (int i = 0; i &lt; row.length; i++)
   * {
   *   span[i] = 1;
   * }
   * addTitle(row, span);
   * </PRE>
   *
   * @param row
   *          Array of strings to print in one row of title.
   * @param span
   *          Array of integers that reflect the number of collumns the
   *          corresponding title string will occupy.
   */
  void addTitle(final String[] row, final int span[])
  {
    // Need to create a new instance of it, otherwise the new values
    // will always overwrite the old values.
    final String[] rowInstance = new String[(row.length)];
    for (int i = 0; i < row.length; i++)
    {
      rowInstance[i] = row[i];
        this.app = app;
    }
    titleTable.addElement(rowInstance);
    titleSpanTable.addElement(span);
  }
  /**
   * Clears title strings.
   */
  void clearTitle()
  {
    titleTable.clear();
    titleSpanTable.clear();
  }
  /**
   * Adds one row of text to output.
   *
   * @param row
   *          Array of strings to print in one row.
   */
  void printRow(final String... row)
  {
    for (int i = 0; i < numCol; i++)
    {
      if (titleAlign == RIGHT)
      {
        final int spaceBefore = curLength[i] - row[i].length();
        printSpaces(spaceBefore);
        app.getOutputStream().print(row[i]);
        if (i < numCol - 1)
        {
          printSpaces(gap);
    /**
     * Adds to the row of strings to be used as the title for the table.
     *
     * @param row
     *            Array of strings to print in one row of title.
     */
    void addTitle(final String[] row) {
        if (row == null) {
            return;
        }
      }
      else if (align == CENTER)
      {
        int space1, space2;
        space1 = (curLength[i] - row[i].length()) / 2;
        space2 = curLength[i] - row[i].length() - space1;
        printSpaces(space1);
        app.getOutputStream().print(row[i]);
        printSpaces(space2);
        if (i < numCol - 1)
        {
          printSpaces(gap);
        final int[] span = new int[row.length];
        for (int i = 0; i < row.length; i++) {
            span[i] = 1;
        }
      }
      else
      {
        app.getOutputStream().print(row[i]);
        if (i < numCol - 1)
        {
          printSpaces(curLength[i] - row[i].length() + gap);
        }
      }
        addTitle(row, span);
    }
    app.getOutputStream().println("");
  }
    /**
     * Adds to the row of strings to be used as the title for the table. Also
     * allows for certain title strings to span multiple collumns The span
     * parameter is an array of integers which indicate how many collumns the
     * corresponding title string will occupy. For a row that is 4 collumns
     * wide, it is possible to have some title strings in a row to 'span'
     * multiple collumns:
     * <P>
     *
     * <PRE>
     * ------------------------------------
     *     Name             Contact
     * First  Last      Email       Phone
     * ------------------------------------
     * Bob    Jones  bob@foo.com   123-4567
     * John   Doe    john@foo.com  456-7890
     * </PRE>
     *
     * In the example above, the title row has a string 'Name' that spans 2
     * collumns. The string 'Contact' also spans 2 collumns. The above is done
     * by passing in to addTitle() an array that contains:
     *
     * <PRE>
     * span[0] = 2; // spans 2 collumns
     * span[1] = 0; // spans 0 collumns, ignore
     * span[2] = 2; // spans 2 collumns
     * span[3] = 0; // spans 0 collumns, ignore
     * </PRE>
     * <P>
     * A span value of 1 is the default. The method addTitle(String[] row)
     * basically does:
     *
     * <PRE>
     * int[] span = new int[row.length];
     * for (int i = 0; i &lt; row.length; i++) {
     *     span[i] = 1;
     * }
     * addTitle(row, span);
     * </PRE>
     *
     * @param row
     *            Array of strings to print in one row of title.
     * @param span
     *            Array of integers that reflect the number of collumns the
     *            corresponding title string will occupy.
     */
    void addTitle(final String[] row, final int[] span) {
        // Need to create a new instance of it, otherwise the new values
        // will always overwrite the old values.
  /**
   * Prints the table title
   */
  void printTitle()
  {
    // Get the longest string for each column and store in curLength[]
    // Scan through title rows
    Enumeration<String[]> elm = titleTable.elements();
    Enumeration<int[]> spanEnum = titleSpanTable.elements();
    while (elm.hasMoreElements())
    {
      final String[] row = elm.nextElement();
      final int[] curSpan = spanEnum.nextElement();
      for (int i = 0; i < numCol; i++)
      {
        // None of the fields should be null, but if it
        // happens to be so, replace it with "-".
        if (row[i] == null)
        {
          row[i] = "-";
        final String[] rowInstance = new String[(row.length)];
        for (int i = 0; i < row.length; i++) {
            rowInstance[i] = row[i];
        }
        titleTable.addElement(rowInstance);
        int len = row[i].length();
        titleSpanTable.addElement(span);
    }
        /*
         * If a title string spans multiple collumns, then the space it occupies
         * in each collumn is at most len/span (since we have gap to take into
         * account as well).
         */
        final int span = curSpan[i];
        int rem = 0;
        if (span > 1)
        {
          rem = len % span;
          len = len / span;
        }
    /**
     * Clears title strings.
     */
    void clearTitle() {
        titleTable.clear();
        titleSpanTable.clear();
    }
        if (curLength[i] < len)
        {
          curLength[i] = len;
    /**
     * Adds one row of text to output.
     *
     * @param row
     *            Array of strings to print in one row.
     */
    void printRow(final String... row) {
        for (int i = 0; i < numCol; i++) {
            if (titleAlign == RIGHT) {
                final int spaceBefore = curLength[i] - row[i].length();
                printSpaces(spaceBefore);
                app.getOutputStream().print(row[i]);
                if (i < numCol - 1) {
                    printSpaces(gap);
                }
            } else if (align == CENTER) {
                int space1, space2;
                space1 = (curLength[i] - row[i].length()) / 2;
                space2 = curLength[i] - row[i].length() - space1;
          if ((span > 1) && ((i + span) <= numCol))
          {
            for (int j = i + 1; j < (i + span); ++j)
            {
              curLength[j] = len;
                printSpaces(space1);
                app.getOutputStream().print(row[i]);
                printSpaces(space2);
                if (i < numCol - 1) {
                    printSpaces(gap);
                }
            } else {
                app.getOutputStream().print(row[i]);
                if (i < numCol - 1) {
                    printSpaces(curLength[i] - row[i].length() + gap);
                }
            }
            /*
             * Add remainder to last collumn in span to avoid round-off errors.
             */
            curLength[(i + span) - 1] += rem;
          }
        }
      }
        app.getOutputStream().println("");
    }
    printBorder();
    elm = titleTable.elements();
    spanEnum = titleSpanTable.elements();
    /**
     * Prints the table title.
     */
    void printTitle() {
        // Get the longest string for each column and store in curLength[]
    while (elm.hasMoreElements())
    {
      final String[] row = elm.nextElement();
      final int[] curSpan = spanEnum.nextElement();
        // Scan through title rows
        Enumeration<String[]> elm = titleTable.elements();
        Enumeration<int[]> spanEnum = titleSpanTable.elements();
        while (elm.hasMoreElements()) {
            final String[] row = elm.nextElement();
            final int[] curSpan = spanEnum.nextElement();
      for (int i = 0; i < numCol; i++)
      {
        int availableSpace = 0;
        final int span = curSpan[i];
            for (int i = 0; i < numCol; i++) {
                // None of the fields should be null, but if it
                // happens to be so, replace it with "-".
                if (row[i] == null) {
                    row[i] = "-";
                }
        if (span == 0)
        {
          continue;
                int len = row[i].length();
                /*
                 * If a title string spans multiple collumns, then the space it
                 * occupies in each collumn is at most len/span (since we have
                 * gap to take into account as well).
                 */
                final int span = curSpan[i];
                int rem = 0;
                if (span > 1) {
                    rem = len % span;
                    len = len / span;
                }
                if (curLength[i] < len) {
                    curLength[i] = len;
                    if ((span > 1) && ((i + span) <= numCol)) {
                        for (int j = i + 1; j < (i + span); ++j) {
                            curLength[j] = len;
                        }
                        /*
                         * Add remainder to last collumn in span to avoid
                         * round-off errors.
                         */
                        curLength[(i + span) - 1] += rem;
                    }
                }
            }
        }
        availableSpace = curLength[i];
        printBorder();
        elm = titleTable.elements();
        spanEnum = titleSpanTable.elements();
        if ((span > 1) && ((i + span) <= numCol))
        {
          for (int j = i + 1; j < (i + span); ++j)
          {
            availableSpace += gap;
            availableSpace += curLength[j];
          }
        while (elm.hasMoreElements()) {
            final String[] row = elm.nextElement();
            final int[] curSpan = spanEnum.nextElement();
            for (int i = 0; i < numCol; i++) {
                int availableSpace = 0;
                final int span = curSpan[i];
                if (span == 0) {
                    continue;
                }
                availableSpace = curLength[i];
                if ((span > 1) && ((i + span) <= numCol)) {
                    for (int j = i + 1; j < (i + span); ++j) {
                        availableSpace += gap;
                        availableSpace += curLength[j];
                    }
                }
                if (titleAlign == RIGHT) {
                    final int spaceBefore = availableSpace - row[i].length();
                    printSpaces(spaceBefore);
                    app.getOutputStream().print(row[i]);
                    if (i < numCol - 1) {
                        printSpaces(gap);
                    }
                } else if (titleAlign == CENTER) {
                    int spaceBefore, spaceAfter;
                    spaceBefore = (availableSpace - row[i].length()) / 2;
                    spaceAfter = availableSpace - row[i].length() - spaceBefore;
                    printSpaces(spaceBefore);
                    app.getOutputStream().print(row[i]);
                    printSpaces(spaceAfter);
                    if (i < numCol - 1) {
                        printSpaces(gap);
                    }
                } else {
                    app.getOutputStream().print(row[i]);
                    if (i < numCol - 1) {
                        printSpaces(availableSpace - row[i].length() + gap);
                    }
                }
            }
            app.getOutputStream().println("");
        }
        printBorder();
    }
    /**
     * Set alignment for title strings.
     *
     * @param titleAlign
     */
    void setTitleAlign(final int titleAlign) {
        this.titleAlign = titleAlign;
    }
    private void printBorder() {
        if (border == null) {
            return;
        }
        if (titleAlign == RIGHT)
        {
          final int spaceBefore = availableSpace - row[i].length();
          printSpaces(spaceBefore);
          app.getOutputStream().print(row[i]);
          if (i < numCol - 1)
          {
            printSpaces(gap);
          }
        }
        else if (titleAlign == CENTER)
        {
          int spaceBefore, spaceAfter;
          spaceBefore = (availableSpace - row[i].length()) / 2;
          spaceAfter = availableSpace - row[i].length() - spaceBefore;
          printSpaces(spaceBefore);
          app.getOutputStream().print(row[i]);
          printSpaces(spaceAfter);
          if (i < numCol - 1)
          {
            printSpaces(gap);
          }
        }
        else
        {
          app.getOutputStream().print(row[i]);
          if (i < numCol - 1)
          {
            printSpaces(availableSpace - row[i].length() + gap);
          }
        // For the value in each column
        for (int i = 0; i < numCol; i++) {
            for (int j = 0; j < curLength[i]; j++) {
                app.getOutputStream().print(border);
            }
        }
      }
      app.getOutputStream().println("");
    }
    printBorder();
  }
  /**
   * Set alignment for title strings
   *
   * @param titleAlign
   */
  void setTitleAlign(final int titleAlign)
  {
    this.titleAlign = titleAlign;
  }
  private void printBorder()
  {
    if (border == null)
    {
      return;
        // For the gap between each column
        for (int i = 0; i < numCol - 1; i++) {
            for (int j = 0; j < gap; j++) {
                app.getOutputStream().print(border);
            }
        }
        app.getOutputStream().println("");
    }
    // For the value in each column
    for (int i = 0; i < numCol; i++)
    {
      for (int j = 0; j < curLength[i]; j++)
      {
        app.getOutputStream().print(border);
      }
    private void printSpaces(final int count) {
        for (int i = 0; i < count; ++i) {
            app.getOutputStream().print(" ");
        }
    }
    // For the gap between each column
    for (int i = 0; i < numCol - 1; i++)
    {
      for (int j = 0; j < gap; j++)
      {
        app.getOutputStream().print(border);
      }
    }
    app.getOutputStream().println("");
  }
  private void printSpaces(final int count)
  {
    for (int i = 0; i < count; ++i)
    {
      app.getOutputStream().print(" ");
    }
  }
}