java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java
branchv_0
changeset 238 4a1864c3e867
parent 237 7e08730da258
child 239 39e6c2ad3571
--- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java	Mon Mar 04 17:06:42 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,308 +0,0 @@
-/**
- * SQL-DK
- * Copyright © 2013 František Kučera (frantovo.cz)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package info.globalcode.sql.dk.formatting;
-
-import info.globalcode.sql.dk.ColorfulPrintWriter;
-import static info.globalcode.sql.dk.ColorfulPrintWriter.*;
-import info.globalcode.sql.dk.Functions;
-import static info.globalcode.sql.dk.Functions.lpad;
-import static info.globalcode.sql.dk.Functions.rpad;
-import static info.globalcode.sql.dk.Functions.repeat;
-import info.globalcode.sql.dk.configuration.PropertyDeclaration;
-import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
-import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
-import java.sql.SQLException;
-import java.sql.SQLXML;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * <p>
- * Prints human-readable output – tables of result sets and text messages with update counts.
- * </p>
- *
- * <p>
- * Longer values might break the table – overflow the cells – see alternative tabular formatters and
- * the {@linkplain #PROPERTY_TRIM} property.
- * </p>
- *
- * @author Ing. František Kučera (frantovo.cz)
- * @see TabularPrefetchingFormatter
- * @see TabularWrappingFormatter
- */
-@PropertyDeclaration(name = COLORFUL, defaultValue = "true", type = Boolean.class, description = COLORFUL_DESCRIPTION)
-@PropertyDeclaration(name = TabularFormatter.PROPERTY_ASCII, defaultValue = "false", type = Boolean.class, description = "whether to use ASCII table borders instead of unicode ones")
-@PropertyDeclaration(name = TabularFormatter.PROPERTY_TRIM, defaultValue = "false", type = Boolean.class, description = "whether to trim the values to fit the column width")
-@PropertyDeclaration(name = TabularFormatter.PROPERTY_HEADER_TYPE, defaultValue = "true", type = Boolean.class, description = "whether to print data types in column headers")
-public class TabularFormatter extends AbstractFormatter {
-
-	private static final Logger log = Logger.getLogger(TabularFormatter.class.getName());
-	public static final String NAME = "tabular"; // bash-completion:formatter
-	private static final String HEADER_TYPE_PREFIX = " (";
-	private static final String HEADER_TYPE_SUFFIX = ")";
-	public static final String PROPERTY_ASCII = "ascii";
-	public static final String PROPERTY_TRIM = "trim";
-	public static final String PROPERTY_HEADER_TYPE = "headerTypes";
-	protected ColorfulPrintWriter out;
-	private boolean firstResult = true;
-	private int[] columnWidth;
-	/**
-	 * use ASCII borders instead of unicode ones
-	 */
-	private final boolean asciiNostalgia;
-	/**
-	 * Trim values if they are longer than cell size
-	 */
-	private final boolean trimValues;
-	/**
-	 * Print data type of each column in the header
-	 */
-	private final boolean printHeaderTypes;
-
-	public TabularFormatter(FormatterContext formatterContext) {
-		super(formatterContext);
-		out = new ColorfulPrintWriter(formatterContext.getOutputStream());
-		asciiNostalgia = formatterContext.getProperties().getBoolean(PROPERTY_ASCII, false);
-		trimValues = formatterContext.getProperties().getBoolean(PROPERTY_TRIM, false);
-		printHeaderTypes = formatterContext.getProperties().getBoolean(PROPERTY_HEADER_TYPE, true);
-		out.setColorful(formatterContext.getProperties().getBoolean(COLORFUL, true));
-	}
-
-	@Override
-	public void writeStartResultSet(ColumnsHeader header) {
-		super.writeStartResultSet(header);
-		printResultSeparator();
-
-		initColumnWidths(header.getColumnCount());
-
-		printTableIndent();
-		printTableBorder("╭");
-
-		List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
-
-		for (ColumnDescriptor cd : columnDescriptors) {
-			// padding: make header cell at least same width as data cells in this column
-			int typeWidth = printHeaderTypes ? cd.getTypeName().length() + HEADER_TYPE_PREFIX.length() + HEADER_TYPE_SUFFIX.length() : 0;
-			cd.setLabel(rpad(cd.getLabel(), getColumnWidth(cd.getColumnNumber()) - typeWidth));
-			updateColumnWidth(cd.getColumnNumber(), cd.getLabel().length() + typeWidth);
-
-			if (!cd.isFirstColumn()) {
-				printTableBorder("┬");
-			}
-			printTableBorder(repeat('─', getColumnWidth(cd.getColumnNumber()) + 2));
-		}
-		printTableBorder("╮");
-		out.println();
-
-		for (ColumnDescriptor cd : columnDescriptors) {
-			if (cd.isFirstColumn()) {
-				printTableIndent();
-				printTableBorder("│ ");
-			} else {
-				printTableBorder(" │ ");
-			}
-			out.print(TerminalStyle.Bright, cd.getLabel());
-			if (printHeaderTypes) {
-				out.print(HEADER_TYPE_PREFIX);
-				out.print(cd.getTypeName());
-				out.print(HEADER_TYPE_SUFFIX);
-			}
-			if (cd.isLastColumn()) {
-				printTableBorder(" │");
-			}
-		}
-		out.println();
-
-		printTableIndent();
-		printTableBorder("├");
-		for (int i = 1; i <= header.getColumnCount(); i++) {
-			if (i > 1) {
-				printTableBorder("┼");
-			}
-			printTableBorder(repeat('─', getColumnWidth(i) + 2));
-		}
-		printTableBorder("┤");
-		out.println();
-
-		out.flush();
-	}
-
-	/**
-	 * Must be called before {@linkplain #updateColumnWidth(int, int)} and
-	 * {@linkplain #getColumnWidth(int)} for each result set.
-	 *
-	 * @param columnCount number of columns in current result set
-	 */
-	protected void initColumnWidths(int columnCount) {
-		if (columnWidth == null) {
-			columnWidth = new int[columnCount];
-		}
-	}
-
-	protected void cleanColumnWidths() {
-		columnWidth = null;
-	}
-
-	@Override
-	public void writeColumnValue(Object value) {
-		super.writeColumnValue(value);
-		writeColumnValueInternal(value);
-	}
-
-	protected void writeColumnValueInternal(Object value) {
-
-		if (isCurrentColumnFirst()) {
-			printTableIndent();
-			printTableBorder("│ ");
-		} else {
-			printTableBorder(" │ ");
-		}
-
-		printValueWithWhitespaceReplaced(toString(value));
-
-		if (isCurrentColumnLast()) {
-			printTableBorder(" │");
-		}
-
-	}
-
-	protected void printValueWithWhitespaceReplaced(String text) {
-		Functions.printValueWithWhitespaceReplaced(out, text, TerminalColor.Cyan, TerminalColor.Red);
-	}
-
-	protected int getColumnWidth(int columnNumber) {
-		return columnWidth[columnNumber - 1];
-	}
-
-	private void setColumnWidth(int columnNumber, int width) {
-		columnWidth[columnNumber - 1] = width;
-	}
-
-	protected void updateColumnWidth(int columnNumber, int width) {
-		int oldWidth = getColumnWidth(columnNumber);
-		setColumnWidth(columnNumber, Math.max(width, oldWidth));
-
-	}
-
-	protected String toString(Object value) {
-		final int width = getColumnWidth(getCurrentColumnsCount());
-		String result;
-		if (value instanceof Number || value instanceof Boolean) {
-			result = lpad(String.valueOf(value), width);
-		} else {
-			if (value instanceof SQLXML) {
-				// TODO: move to a common method, share with other formatters
-				try {
-					value = ((SQLXML) value).getString();
-				} catch (SQLException e) {
-					log.log(Level.SEVERE, "Unable to format XML", e);
-				}
-			}
-
-			result = rpad(String.valueOf(value), width);
-		}
-		// ?	value = (boolean) value ? "✔" : "✗";
-
-		if (trimValues && result.length() > width) {
-			result = result.substring(0, width - 1) + "…";
-		}
-
-		return result;
-	}
-
-	@Override
-	public void writeEndRow() {
-		super.writeEndRow();
-		writeEndRowInternal();
-	}
-
-	public void writeEndRowInternal() {
-		out.println();
-		out.flush();
-	}
-
-	@Override
-	public void writeEndResultSet() {
-		int columnCount = getCurrentColumnsHeader().getColumnCount();
-		super.writeEndResultSet();
-
-		printTableIndent();
-		printTableBorder("╰");
-		for (int i = 1; i <= columnCount; i++) {
-			if (i > 1) {
-				printTableBorder("┴");
-			}
-			printTableBorder(repeat('─', getColumnWidth(i) + 2));
-		}
-		printTableBorder("╯");
-		out.println();
-
-		cleanColumnWidths();
-
-		out.print(TerminalColor.Yellow, "Record count: ");
-		out.println(getCurrentRowCount());
-		out.bell();
-		out.flush();
-	}
-
-	@Override
-	public void writeUpdatesResult(int updatedRowsCount) {
-		super.writeUpdatesResult(updatedRowsCount);
-		printResultSeparator();
-		out.print(TerminalColor.Red, "Updated records: ");
-		out.println(updatedRowsCount);
-		out.bell();
-		out.flush();
-	}
-
-	@Override
-	public void writeEndDatabase() {
-		super.writeEndDatabase();
-		out.flush();
-	}
-
-	private void printResultSeparator() {
-		if (firstResult) {
-			firstResult = false;
-		} else {
-			out.println();
-		}
-	}
-
-	protected void printTableBorder(String border) {
-		if (asciiNostalgia) {
-			border = border.replaceAll("─", "-");
-			border = border.replaceAll("│", "|");
-			border = border.replaceAll("[╭┬╮├┼┤╰┴╯]", "+");
-		}
-
-		out.print(TerminalColor.Green, border);
-	}
-
-	protected void printTableIndent() {
-		out.print(" ");
-	}
-
-	/**
-	 * @return whether should print only ASCII characters instead of unlimited Unicode.
-	 */
-	protected boolean isAsciiNostalgia() {
-		return asciiNostalgia;
-	}
-}