Utility class for printing aligned columns of text : Console « Development Class « Java






Utility class for printing aligned columns of text

   

/*
 * @(#)VMMetrics.java  1.3 04/01/05
 *
 * Copyright (c) 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

/*
 * @(#)MultiColumnPrinter.java  1.3 04/09/15
 *
 * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved
 * SUN PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 *
 */

import java.util.Enumeration;
import java.util.Vector;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;

/**
 * Utility class for printing aligned collumns of text. How/where
 * the text is printed is determined by the abstract methods
 * doPrint(String) and doPrintln(String). The typical case is to 
 * create a subclass and make these methods print the string to standard 
 * out or error.
 * <P>
 * This class allows you to specify:
 * <UL>
 * <LI>The number of collumns in the output. This will determine
 * the dimension of the string arrays passed to add(String[])
 * or addTitle(String[]).
 * <LI>spacing/gap between columns
 * <LI>character to use for title border (null means no border)
 * <LI>column alignment. Only LEFT/CENTER is supported for now.
 * </UL>
 *
 * <P>
 * Example usage:
 * <PRE>
 *  MyPrinter  mp = new MyPrinter(3, 2, "-");
 *  String    oneRow[] = new String [ 3 ];
 *  oneRow[0] = "User Name";
 *  oneRow[1] = "Email Address";
 *  oneRow[2] = "Phone Number";
 *  mp.addTitle(oneRow);
 *
 *  oneRow[0] = "Bob";
 *  oneRow[1] = "bob@foo.com";
 *  oneRow[2] = "123-4567";
 *  mp.add(oneRow);
 *
 *  oneRow[0] = "John";
 *  oneRow[1] = "john@foo.com";
 *  oneRow[2] = "456-7890";
 *  mp.add(oneRow);
 *  mp.print();
 * </PRE>
 *
 * <P>
 * The above would print:
 * <P>
 * <PRE>
 *  --------------------------------------
 *  User Name  Email Address  Phone Number
 *  --------------------------------------
 *  Bob        bob@foo.com    123-4567
 *  John       john@foo.com   456-7890
 * </PRE>
 *
 *<P>
 * This class also supports multi-row titles and having title
 * strings spanning multiple collumns. Example usage:
 * <PRE>
 *     TestPrinter  tp = new TestPrinter(4, 2, "-");
 *     String    oneRow[] = new String [ 4 ];
 *     int[]    span = new int[ 4 ];
 *
 *     span[0] = 2; // spans 2 collumns
 *     span[1] = 0; // spans 0 collumns
 *     span[2] = 2; // spans 2 collumns
 *     span[3] = 0; // spans 0 collumns
 *
 *     tp.setTitleAlign(CENTER);
 *     oneRow[0] = "Name";
 *     oneRow[1] = "";
 *     oneRow[2] = "Contact";
 *     oneRow[3] = "";
 *     tp.addTitle(oneRow, span);
 * 
 *     oneRow[0] = "First";
 *     oneRow[1] = "Last";
 *     oneRow[2] = "Email";
 *     oneRow[3] = "Phone";
 *     tp.addTitle(oneRow);
 * 
 *     oneRow[0] = "Bob";
 *     oneRow[1] = "Jones";
 *     oneRow[2] = "bob@foo.com";
 *     oneRow[3] = "123-4567";
 *     tp.add(oneRow);
 * 
 *     oneRow[0] = "John";
 *     oneRow[1] = "Doe";
 *     oneRow[2] = "john@foo.com";
 *     oneRow[3] = "456-7890";
 *     tp.add(oneRow);
 * 
 *     tp.println();
 * </PRE>
 *
 * <P>
 * The above would print:
 * <P>
 * <PRE>
 *      ------------------------------------
 *          Name             Contact          
 *      First  Last      Email       Phone  
 *      ------------------------------------
 *      Bob    Jones  bob@foo.com   123-4567
 *      John   Doe    john@foo.com  456-7890
 * </PRE>
 *
 */
public abstract class MultiColumnPrinter {

    final public static int  LEFT  = 0;
    final public static int  CENTER  = 1;

    /*
     * Sets the default sorting behavior.
     * When set to true, the table entries are sorted unless otherwise
     * specified in a constructor.
     */
    final private static boolean  DEFAULT_SORT = true;

    private int numCol = 2;
    private int gap = 4;
    private int align = CENTER;
    private int titleAlign = CENTER;
    private String border = null;

    private Vector table = null;
    private Vector titleTable = null;
    private Vector titleSpanTable = null;
    private int curLength[];

    private boolean sortNeeded = DEFAULT_SORT;
    private int[] keyCriteria = null;

    /**
     * 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
     * @param sort true if the output is sorted; false otherwise
     *
     * REVISIT: Possibly adding another argument that specifies which ones can
     * be truncated (xxx...)
     */
    public MultiColumnPrinter(int numCol, int gap, String border, 
            int align, boolean sort) {

        table = new Vector();
        titleTable = new Vector();
        titleSpanTable = new Vector();
        curLength = new int[numCol];

        this.numCol = numCol;
        this.gap = gap;
        this.border = border;
        this.align = align;
        this.titleAlign = LEFT;
  this.sortNeeded = sort;
    }

    /**
     * Creates a new sorted 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
     */
    public MultiColumnPrinter(int numCol, int gap, String border, int align) {
  this(numCol, gap, border, align, DEFAULT_SORT);
    }

    /**
     * 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
     */
    public MultiColumnPrinter(int numCol, int gap, String border) {
  this(numCol, gap, border, LEFT);
    }

    /**
     * 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
     */
    public MultiColumnPrinter(int numCol, int gap) {
  this(numCol, gap, null, LEFT);
    }

    /**
     * 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.
     */
    public void addTitle(String[] row) {
  if (row == null)
      return;

  int[] span = new int [ row.length ];
  for (int i = 0; i < row.length; i++) {
      span[i] = 1;
  }
  
  addTitle(row, span);
    }

    /**
     * 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 < 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.
     */
    public void addTitle(String[] row, int span[]) {
  // Need to create a new instance of it, otherwise the new values will
  // always overwrite the old values.

  String[] rowInstance = new String[(row.length)];
  for (int i = 0; i < row.length; i++) {
      rowInstance[i] = row[i];
  }
  titleTable.addElement(rowInstance);

  titleSpanTable.addElement(span);
    }

    /**
     * Set alignment for title strings
     *
     * @param titleAlign
     */
    public void setTitleAlign(int titleAlign)  {
  this.titleAlign = titleAlign;
    }

    /**
     * Adds one row of text to output.
     *
     * @param row Array of strings to print in one row.
     */
    public void add(String[] row) {
  // Need to create a new instance of it, otherwise the new values will
  // always overwrite the old values.
  String[] rowInstance = new String[(row.length)];
  for (int i = 0; i < row.length; i++) {
      rowInstance[i] = row[i];
  }
  table.addElement(rowInstance);
    }

    /**
     * Clears title strings.
     */
    public void clearTitle()  {
  titleTable.clear();
  titleSpanTable.clear();
    }

    /**
     * Clears strings.
     */
    public void clear()  {
  table.clear();

  if (curLength != null)  {
            for (int i = 0; i < curLength.length; ++i)  {
                curLength[i] = 0;
            }
        }
    }

    /**
     * Prints the multi-column table, including the title.
     */
    public void print() {
  print(true);
    }

    /**
     * Prints the multi-column table.
     * 
     * @param printTitle Specifies if the title rows should be printed.
     */
    public void print(boolean printTitle) {

    // REVISIT:
    // Make sure you take care of curLength and row being null value cases.


  // Get the longest string for each column and store in curLength[]

  // Scan through title rows
  Enumeration elm = titleTable.elements();
  Enumeration spanEnum = titleSpanTable.elements();
  int rowNum = 0;
  while (elm.hasMoreElements()) {
      String[] row = (String[])elm.nextElement();
      int[] curSpan = (int[])spanEnum.nextElement();

      for (int i = 0; i < numCol; i++) {
    // Fix for 4627901: NullPtrException seen when 
    // execute 'jmqcmd list dur'
    // This happens when a field to be listed is null.
    // None of the fields should be null, but if it
    // happens to be so, replace it with "-".
                if (row[i] == null) 
                    row[i] = "-";

    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).
     */
    int span = curSpan[i], 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;
        }
    }
      }
      ++rowNum;
  }

  // Scan through rest of rows
  elm = table.elements();
  while (elm.hasMoreElements()) {
      String[] row = (String[])elm.nextElement();
      for (int i = 0; i < numCol; i++) {

                // Fix for 4627901: NullPtrException seen when 
                // execute 'jmqcmd list dur'
                // This happens when a field to be listed is null.
                // None of the fields should be null, but if it
                // happens to be so, replace it with "-".
                if (row[i] == null) 
                    row[i] = "-";

    if (curLength[i] < row[i].length())
        curLength[i] = row[i].length();
      }
  }

  /*
   * Print title
   */
  if (printTitle)  {
      printBorder();
      elm = titleTable.elements();
      spanEnum = titleSpanTable.elements();

      while (elm.hasMoreElements()) {
          String[] row = (String[])elm.nextElement();
          int[] curSpan = (int[])spanEnum.nextElement();

          for (int i = 0; i < numCol; i++) {
        int availableSpace = 0, 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 == CENTER)  {
            int space_before, space_after;
            space_before = (availableSpace-row[i].length())/2;
            space_after = availableSpace-row[i].length() - space_before;

            printSpaces(space_before);
                  doPrint(row[i]);
            printSpaces(space_after);
            if (i < numCol-1) printSpaces(gap);
        } else  {
                  doPrint(row[i]);
            if (i < numCol-1) printSpaces(availableSpace-row[i].length()+gap);
        }

          }
          doPrintln("");
      }
      printBorder();
  }

  if (sortNeeded)
      printSortedTable();
  else
      printUnsortedTable();
    }

    /*
     * Prints the table entries in the sorted order.
     */
    private void printSortedTable() {
  // Sort the table entries
        TreeMap sortedTable = new TreeMap();
        Enumeration elm = table.elements();
        while (elm.hasMoreElements()) {
            String[] row = (String[])elm.nextElement();

      // If keyCriteria contains valid info use that
      // to create the key; otherwise, use the default row[0]
      // for the key.
      if (keyCriteria != null && keyCriteria.length > 0) {
    String key = getKey(row);
    if (key != null)
                   sortedTable.put(key, row);
    else
                   sortedTable.put(row[0], row);
      } else {  
                sortedTable.put(row[0], row);
      }
        }

  // Iterate through the table entries
        Iterator iterator = sortedTable.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry)iterator.next();
            String[] row = ((String[])entry.getValue());

      printRow(row);
  }
    }

    /*
     * Creates the key for the current row based on the
     * criteria specified by setKeyCriteria().
     * If key cannot be created by the criteria, it simply returns
     * null.
     *
     * Examples:
     * String[] row = {"foo", "bar", "hello");
     *
     * int[] keyCriteria = {0};
     * key = "foo";
     *
     * int[] keyCriteria = {0, 1};
     * key = "foobar";
     *
     * int[] keyCriteria = {2, 1};
     * key = "hellobar";
     *
     * int[] keyCriteria = {4};
     * key = null;
     */
    private String getKey(String[] row) {
  String key = "";
  
  for (int i = 0; i < keyCriteria.length; i++) {
      int content = keyCriteria[i];
      try {
          key = key + row[content];
      } catch (ArrayIndexOutOfBoundsException ae) {
    // Happens when keyCriteria[] contains an index that
     // does not exist in 'row'.
    return null;
      }
  }
  return key;
    }

    /*
     * Prints the table entries in the order they were entered.
     */
    private void printUnsortedTable() {
        Enumeration elm = table.elements();
        while (elm.hasMoreElements()) {
            String[] row = (String[])elm.nextElement();

      printRow(row);
        }
    }

    private void printRow(String[] row) {
            for (int i = 0; i < numCol; i++) {
                    if (align == CENTER)  {
                        int space1, space2;
                        space1 = (curLength[i]-row[i].length())/2;
                        space2 = curLength[i]-row[i].length() - space1;

                        printSpaces(space1);
                        doPrint(row[i]);
                        printSpaces(space2);
                        if (i < numCol-1) printSpaces(gap);
                    } else  {
                        doPrint(row[i]);
                        if (i < numCol-1) printSpaces(curLength[i]-row[i].length()+gap);
                    }
            }
            doPrintln("");
    }

    /**
     * Prints the multi-column table, with a carriage return.
     */
    public void println() {
  print();
  doPrintln("");
    }

    private void printSpaces(int count)  {
        for (int i = 0; i < count; ++i)  {
            doPrint(" ");
        }
    }

    private void printBorder() {

  int colNum = 1;
  if (border == null) return;

  // For the value in each column
  for (int i = 0; i < numCol; i++) {
      for (int j = 0; j < curLength[i]; j++) {
                doPrint(border);
      }  
  }

  // For the gap between each column
  for (int i = 0; i < numCol-1; i++) {
      for (int j = 0; j < gap; j++) {
                doPrint(border);
      }  
  }
  doPrintln("");
    }

    /*
     * Sets the criteria for the key.
     * new int[] {0, 1} means use the first and the second
     * elements of the array.
     */
    public void setKeyCriteria(int[] criteria) {
  this.keyCriteria = criteria;
    }

    /**
     * Method that does the actual printing. Override this method to
     * print to your destination of choice (stdout, stream, etc).
     *
     * @param str String to print.
     */
    public abstract void doPrint(String str);

    /**
     * Method that does the actual printing. Override this method to
     * print to your destination of choice (stdout, stream, etc).
     *
     * This method also prints a newline at the end of the string.
     *
     * @param str String to print.
     */
    public abstract void doPrintln(String str);
}

          
    
  








JMQ-monitoring.zip( 18 k)

Related examples in the same category

1.Turn System.out into a PrintWriterTurn System.out into a PrintWriter
2.Output to standard output and standard error; and input from standard input.Output to standard output and standard error; and input from standard input.
3.VarArgsDemo - show 1.5 variable argumentsVarArgsDemo - show 1.5 variable arguments
4.How to read from standard inputHow to read from standard input
5.How to deal with the console parametersHow to deal with the console parameters
6.Read input from consoleRead input from console
7.Command line input
8.Read an int from Standard Input
9.Read an int from Standard Input, using 1.5
10.SimpleCalc -- simple calculator using 1.5 java.util.Scanner
11.Show use of Argv to get an integer value from command lineShow use of Argv to get an integer value from command line
12.Java program to calculate the area of a circleJava program to calculate the area of a circle
13.Java program to demonstrate menu selectionJava program to demonstrate menu selection
14.Processing the command line
15.A representation of the command line arguments passed to a Java class' main(String[]) method
16.Helper class for storing long command lines inside temporary file.
17.CommandLine Parser
18.This parses command line arguments optimized for ease of programmer use.
19.Console read and write Utils