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

de.vandermeer.asciitable.commons.package-info Maven / Gradle / Ivy

/* Copyright 2014 Sven van der Meer 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Common artifacts for the ASCII tables.
 * 
 * 
 * 

Array Transformations

* Collections of utility methods to manipulate (transform) arrays. * They solve a number of common problems when using multi-dimensional arrays (as the table implementations do for rendering, here 2-dimensional arrays): *
    *
  • a {@code toString()} method for 2-dimensional arrays (I didn't find anyone elsewhere) - {@link de.vandermeer.asciitable.commons.ArrayTransformations#ARRAY_TO_STRING(Object[][])}
  • *
  • a method to flip 2-dimensional arrays, making it possible to easily use loops e.g. for rendering - {@link de.vandermeer.asciitable.commons.ArrayTransformations#FLIP_ARRAY(String[][])}
  • *
  • a method to normalize 2-dimensional arrays, meaning to add cells with null or empty content so that all rows have the same number of columns - {@link de.vandermeer.asciitable.commons.ArrayTransformations#NORMALISE_ARRAY(int, String[][])}
  • *
  • a method to wrap text lines in order to maintain an overall column length - {@link de.vandermeer.asciitable.commons.ArrayTransformations#WRAP_LINES(int, Object)}
  • *
* * *

The Problem

*

* Let's call a row a line in a table. * A table can have multiple (basically any number of ) rows. * Let's call a column a part of a row with special formatting. * A row can have one or more columns, with each row of a the same table having the same number of columns. * Let's call a cell a part of the table identified by row and column. * For instance the 2nd column of the 3rd row would be cell 3-2. *

* * Filling a table with content means to add rows with their columns, one row at a time until all rows are added. * The tables here provide and {@code addRow()} method with variable argument, checking per table that the number of columns (objects in the argument) is equal per row added. * If all cells fit in the defined (or calculated) width of the columns and tables, nothing special is required. * Here, one can use lists or sets or arrays to represent the rows with their columns and easily render them. * For instance, the following code creates a table with all cells fitting in the calculated width (2 rows with 3 columns each and width of 19): *
{@code
	V2_AsciiTable at = new V2_AsciiTable();
	at.addRule();
	at.addRow("1-1", "1-2", "1-3");
	at.addRule();
	at.addRow("2-1", "2-2", "2-3");
	at.addRule();
 * }
* With the rendered output of (using a renderer with the {@link de.vandermeer.asciitable.v2.themes.V2_E_TableThemes#UTF_LIGHT} theme): *
	┌─────┬─────┬─────┐
	│ 1-1 │ 1-2 │ 1-3 │
	├─────┼─────┼─────┤
	│ 2-1 │ 2-2 │ 2-3 │
	└─────┴─────┴─────┘
 * 
* * However, if only one of the cells is "over-width" this simple approach will not work anymore. * For instance using the following code for the first row will create a problem: *
{@code
	at.addRow("1-1", "1-2 text", "1-3");
 * }
* * The expected rendered table would need to wrap the over size cell 1-2 resulting in the following output: *
	┌─────┬─────┬─────┐
	│ 1-1 │ 1-2 │ 1-3 │
	│     │ tex │     │
	│     │ t   │     │
	├─────┼─────┼─────┤
	│ 2-1 │ 2-2 │ 2-3 │
	└─────┴─────┴─────┘
 * 
* * This means to actually add (for the render process), multiple lines to cells 1-1 and 1-3 to match up with the new added lines in cell 2-2. * Simply using lists or sets or even arrays may (can) result in complicated code. * The approach taken in the ASCII table is to ignore this problem until a table is to be rendered. * Then the methods introduced above come in handy to calculate a 2-dimensional array solving the problem described here (and a few more). * * *

The Solution - Wrap and Normalize

*

* A table is filled as described above: row by row with each row having columns and the content of each column set by an object. * When filling a table, nothing is done beside creating an array of objects as columns per row added to the table. *

* *

* A renderer then sees a table as a set of rows, each of which is an array of objects. * The objects are the content of cells, their respective {@code toString()} method being used to create the content. * The renderer also has the width of columns and the overall table width. *

* *

* Per row, the renderer then creates a 2-dimensional array. * In the simple case that all cells fit in the given width, this array will have a width of 3 (3 columns per row) and a length of 1 (nothing done with the cell content) per row. *

* * In the simple case (all cells fit) described above, the renderer will simply create the following content arrays for row 1 (top) and row 2 (bottom): *
	[0][0]: 1-1
	[1][0]: 1-2
	[2][0]: 1-3

	[0][0]: 2-1
	[1][0]: 2-2
	[2][0]: 2-3

 * 
* *

* For the second example above, with an over-size column, * the renderer will need to first wrap the contents of cell 1-2 * and then normalize the content array of row 1 adding the new lines in cell 1-1 and cell 1-3 * to match the new created lines for the wrapped lines in cell 1-2. *

* *

* To do that, the renderer uses the two array transformation methods * {@link de.vandermeer.asciitable.commons.ArrayTransformations#WRAP_LINES(int, Object)} to wrap the lines in cell 1-2 and * {@link de.vandermeer.asciitable.commons.ArrayTransformations#NORMALISE_ARRAY(int, String[][])} to normalize the cells 1-1 and 1-3. *

* * The content arrays for row 1 and 2 look then as shown below. * Row 1 has added lines for cell 1-1 and 1-3 and wrapped lines for cell 1-2 (the content of {@code 0} in those added lines means empty line). * Row 2 is the same as for the simple example. *
	[0][0]: 1-1
	[0][1]: 0
	[0][2]: 0
	[1][0]: 1-2
	[1][1]: tex
	[1][2]: t
	[2][0]: 1-3
	[2][1]: 0
	[2][2]: 0

	[0][0]: 2-1
	[1][0]: 2-2
	[2][0]: 2-3
 * 
* * *

The Solution - Flip

*

* Once the renderer has created a content array per row with wrapped lines and normalized cells, the next problem is to create the actual output. * As can be seen in the last example above (wrapped lines for cell 1-2), using the originally created array is not very efficient, * because the renderer will need complicated nested loops to reach all cells. *

* *

* However, if we flip the content array (do a horizontal and vertical transformation), we will get a content array that has per first dimension all cells to be printed. * This is what {@link de.vandermeer.asciitable.commons.ArrayTransformations#FLIP_ARRAY(String[][])} does. *

* * For the simple example above, created content array looked like this: *
	[0][0]: 1-1
	[1][0]: 1-2
	[2][0]: 1-3

	[0][0]: 2-1
	[1][0]: 2-2
	[2][0]: 2-3
 * 
* * Flipping these arrays will result in the following: *
	[0][0]: 1-1
	[0][1]: 1-2
	[0][2]: 1-3

	[0][0]: 2-1
	[0][1]: 2-2
	[0][2]: 2-3
 * 
* *

* Now, it is a simple loop throw the arrays first dimension for all printable lines, and a simple loop through the arrays second dimension for all printable cells. *

* * Similar for the over-size example above. The original content arrays looked like this: *
	[0][0]: 1-1
	[0][1]: 0
	[0][2]: 0
	[1][0]: 1-2
	[1][1]: tex
	[1][2]: t
	[2][0]: 1-3
	[2][1]: 0
	[2][2]: 0

	[0][0]: 2-1
	[1][0]: 2-2
	[2][0]: 2-3
 * 
* * Fliping the arrays will result in the following arrays for the renderer: *
	[0][0]: 1-1
	[0][1]: 1-2
	[0][2]: 1-3
	[1][0]: 0
	[1][1]: tex
	[1][2]: 0
	[2][0]: 0
	[2][1]: t
	[2][2]: 0

	[0][0]: 2-1
	[0][1]: 2-2
	[0][2]: 2-3
 * 
* * *

Complete solution - creating a content array

* Taking version 2 and the over-size example above, a complete solution is implemented in {@link de.vandermeer.asciitable.v2.render.RenderUtilities#createContentArray(Object[], int[], int[])}. * The method receives the original content array of a row plus an integer array with column width and an integer array with padding per column (V2 introduced padding for columns). * The following code shows how a renderer would call this method: *
{@code
	String[][] ar;
	ar = V2_Utilities.createContentArray(new Object[]{"1-1", "1-2 text", "1-3"}, new int[]{5, 5, 5}, new int[]{1, 1, 1});
 * }
* * The method then creates a return array: *
{@code
	String[][] ret = new String[width.length][];
 * }
* * Per entry in the given content array, it then determines if lines have to be wrapped (content of {@code null} means column span): *
{@code
	int length = 0;
	for(int i=0; i0){
			length = length - padding[i]*2;
		}
		ret[i] = ArrayTransformations.WRAP_LINES(length, o);
		length = 0;
	}
 * }
* * Once the line wrapping is done, the resulting array can be normalized: *
{@code
	ret = ArrayTransformations.NORMALISE_ARRAY(width.length, ret);
 * }
* * And then finally flipped and returned: *
{@code
	ret = ArrayTransformations.FLIP_ARRAY(ret);
	return ret;
 * }
* * * *

A ToString Style

* A style definition helping to simplify {@code toString()} methods using {@link org.apache.commons.lang3.builder.StandardToStringStyle}. * * * *

A Table Exception

* {@link de.vandermeer.asciitable.commons.TableException} implements a runtime exception. * This is used in the tables for instance for initialization substituting for more common runtime or illegal argument exceptions. * * * * @author Sven van der Meer <[email protected]> * @version v1.0.0 build 160319 (19-Mar-16) for Java 1.7 */ package de.vandermeer.asciitable.commons;




© 2015 - 2025 Weber Informatics LLC | Privacy Policy