BarChartFormatter: first version v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 30 Aug 2015 02:28:15 +0200
branchv_0
changeset 22436db9fd27436
parent 223 195d969a1fb1
child 225 906f767ef9b3
BarChartFormatter: first version
java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/BarChartFormatter.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java
     1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java	Sun Aug 30 02:24:36 2015 +0200
     1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java	Sun Aug 30 02:28:15 2015 +0200
     1.3 @@ -19,7 +19,7 @@
     1.4  
     1.5  import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
     1.6  import static info.globalcode.sql.dk.Functions.findByName;
     1.7 -import info.globalcode.sql.dk.formatting.DsvFormatter;
     1.8 +import info.globalcode.sql.dk.formatting.BarChartFormatter;
     1.9  import info.globalcode.sql.dk.formatting.SilentFormatter;
    1.10  import info.globalcode.sql.dk.formatting.SingleRecordFormatter;
    1.11  import info.globalcode.sql.dk.formatting.SingleValueFormatter;
    1.12 @@ -73,7 +73,9 @@
    1.13  		l.add(new FormatterDefinition(TabularPrefetchingFormatter.NAME, TabularPrefetchingFormatter.class.getName()));
    1.14  		l.add(new FormatterDefinition(TabularWrappingFormatter.NAME, TabularWrappingFormatter.class.getName()));
    1.15  		l.add(new FormatterDefinition(TeXFormatter.NAME, TeXFormatter.class.getName()));
    1.16 -		l.add(new FormatterDefinition(DsvFormatter.NAME, DsvFormatter.class.getName()));
    1.17 +		//l.add(new FormatterDefinition(DsvFormatter.NAME, DsvFormatter.class.getName()));
    1.18 +		//l.add(new FormatterDefinition(SystemCommandExecutor.NAME, SystemCommandExecutor.class.getName()));
    1.19 +		l.add(new FormatterDefinition(BarChartFormatter.NAME, BarChartFormatter.class.getName()));
    1.20  		buildInFormatters = Collections.unmodifiableCollection(l);
    1.21  	}
    1.22  
    1.23 @@ -88,7 +90,7 @@
    1.24  
    1.25  	/**
    1.26  	 * @param name
    1.27 -	 * @return 
    1.28 +	 * @return
    1.29  	 * @throws ConfigurationException if no database with this name is configured
    1.30  	 */
    1.31  	public DatabaseDefinition getDatabase(String name) throws ConfigurationException {
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/BarChartFormatter.java	Sun Aug 30 02:28:15 2015 +0200
     2.3 @@ -0,0 +1,96 @@
     2.4 +/**
     2.5 + * SQL-DK
     2.6 + * Copyright © 2015 František Kučera (frantovo.cz)
     2.7 + *
     2.8 + * This program is free software: you can redistribute it and/or modify
     2.9 + * it under the terms of the GNU General Public License as published by
    2.10 + * the Free Software Foundation, either version 3 of the License, or
    2.11 + * (at your option) any later version.
    2.12 + *
    2.13 + * This program is distributed in the hope that it will be useful,
    2.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    2.16 + * GNU General Public License for more details.
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License
    2.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    2.20 + */
    2.21 +package info.globalcode.sql.dk.formatting;
    2.22 +
    2.23 +import info.globalcode.sql.dk.Functions;
    2.24 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
    2.25 +import info.globalcode.sql.dk.logging.LoggerProducer;
    2.26 +import java.math.BigDecimal;
    2.27 +import java.math.MathContext;
    2.28 +import java.math.RoundingMode;
    2.29 +import java.util.List;
    2.30 +import java.util.logging.Level;
    2.31 +import java.util.logging.Logger;
    2.32 +
    2.33 +/**
    2.34 + *
    2.35 + * @author Ing. František Kučera (frantovo.cz)
    2.36 + */
    2.37 +@PropertyDeclaration(name = BarChartFormatter.PROPERTY_PRECISION, type = Integer.class, defaultValue = BarChartFormatter.PROPERTY_PRECISION_DEFAULT, description = "number of characters representing 100 % in the bar chart")
    2.38 +public class BarChartFormatter extends TabularPrefetchingFormatter {
    2.39 +
    2.40 +	public static final String NAME = "barchart"; // bash-completion:formatter
    2.41 +	public static final String PROPERTY_PRECISION = "precision";
    2.42 +	protected static final String PROPERTY_PRECISION_DEFAULT = "100";
    2.43 +	private static final MathContext mathContext = MathContext.DECIMAL128;
    2.44 +	public static final Logger log = LoggerProducer.getLogger();
    2.45 +	private final BigDecimal chartPrecision;
    2.46 +	private final char chartFull;
    2.47 +	private final char chartEmpty;
    2.48 +
    2.49 +	public BarChartFormatter(FormatterContext formatterContext) {
    2.50 +		super(formatterContext);
    2.51 +		chartPrecision = BigDecimal.valueOf(formatterContext.getProperties().getInteger(PROPERTY_PRECISION, Integer.parseInt(PROPERTY_PRECISION_DEFAULT)));
    2.52 +		chartFull = isAsciiNostalgia() ? '#' : '█';
    2.53 +		chartEmpty = isAsciiNostalgia() ? '~' : '░';
    2.54 +		// TODO: consider using partial blocks for more precision: https://en.wikipedia.org/wiki/Block_Elements
    2.55 +	}
    2.56 +
    2.57 +	@Override
    2.58 +	protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
    2.59 +		super.postprocessPrefetchedResultSet(currentHeader, currentResultSet);
    2.60 +
    2.61 +		updateColumnWidth(currentHeader.getColumnCount(), chartPrecision.intValue());
    2.62 +
    2.63 +		BigDecimal maximum = BigDecimal.ZERO;
    2.64 +		BigDecimal minimum = BigDecimal.ZERO;
    2.65 +		int lastIndex = currentHeader.getColumnCount() - 1;
    2.66 +
    2.67 +		try {
    2.68 +			for (Object[] row : currentResultSet) {
    2.69 +				Object valueObject = row[lastIndex];
    2.70 +				if (valueObject != null) {
    2.71 +					BigDecimal value = new BigDecimal(valueObject.toString());
    2.72 +					maximum = maximum.max(value);
    2.73 +					minimum = minimum.min(value);
    2.74 +				}
    2.75 +			}
    2.76 +
    2.77 +			BigDecimal range = maximum.subtract(minimum);
    2.78 +
    2.79 +			for (Object[] row : currentResultSet) {
    2.80 +				Object valueObject = row[lastIndex];
    2.81 +				if (valueObject != null) {
    2.82 +					BigDecimal value = new BigDecimal(valueObject.toString());
    2.83 +					BigDecimal valueFromMinimum = value.subtract(minimum);
    2.84 +
    2.85 +					BigDecimal points = chartPrecision.divide(range, mathContext).multiply(valueFromMinimum, mathContext);
    2.86 +					int pointsRounded = points.setScale(0, RoundingMode.HALF_UP).intValue();
    2.87 +					row[lastIndex] = Functions.repeat(chartFull, pointsRounded) + Functions.repeat(chartEmpty, chartPrecision.intValue() - pointsRounded);
    2.88 +				}
    2.89 +			}
    2.90 +
    2.91 +		} catch (NumberFormatException e) {
    2.92 +			// https://en.wiktionary.org/wiki/parsable
    2.93 +			log.log(Level.SEVERE, "Last column must be number or an object with toString() value parsable to a number.");
    2.94 +			// FIXME: throw FormatterException
    2.95 +			throw e;
    2.96 +		}
    2.97 +	}
    2.98 +
    2.99 +}
     3.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java	Sun Aug 30 02:24:36 2015 +0200
     3.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java	Sun Aug 30 02:28:15 2015 +0200
     3.3 @@ -277,4 +277,11 @@
     3.4  	protected void printTableIndent() {
     3.5  		out.print(" ");
     3.6  	}
     3.7 +
     3.8 +	/**
     3.9 +	 * @return whether should print only ASCII characters instead of unlimited Unicode.
    3.10 +	 */
    3.11 +	protected boolean isAsciiNostalgia() {
    3.12 +		return asciiNostalgia;
    3.13 +	}
    3.14  }
     4.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java	Sun Aug 30 02:24:36 2015 +0200
     4.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java	Sun Aug 30 02:28:15 2015 +0200
     4.3 @@ -86,6 +86,8 @@
     4.4  	public void writeEndResultSet() {
     4.5  		prefetchDone = true;
     4.6  
     4.7 +		postprocessPrefetchedResultSet(currentHeader, currentResultSet);
     4.8 +
     4.9  		super.writeStartResultSet(currentHeader);
    4.10  
    4.11  		for (Object[] row : currentResultSet) {
    4.12 @@ -103,4 +105,15 @@
    4.13  		super.writeEndResultSet();
    4.14  		prefetchDone = false;
    4.15  	}
    4.16 +
    4.17 +	/**
    4.18 +	 * Optional post-processing – override in sub-classes if needed.
    4.19 +	 * Don't forget to {@linkplain #updateColumnWidth(int, int)}
    4.20 +	 *
    4.21 +	 * @param currentHeader
    4.22 +	 * @param currentResultSet
    4.23 +	 */
    4.24 +	protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
    4.25 +	}
    4.26 +
    4.27  }