/** * DataCleaner (community edition) * Copyright (C) 2014 Neopost - Customer Information Management * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.datacleaner.result.renderer; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.List; import org.datacleaner.api.RendererBean; import org.datacleaner.result.Crosstab; import org.datacleaner.result.CrosstabDimension; import org.datacleaner.result.CrosstabResult; import org.datacleaner.result.ResultProducer; import org.datacleaner.util.LabelUtils; import org.datacleaner.util.ReflectionUtils; @RendererBean(TextRenderingFormat.class) public class CrosstabTextRenderer extends AbstractRenderer<CrosstabResult, String> { private static class TextCrosstabRendererCallback implements CrosstabRendererCallback<String> { private final NumberFormat decimalFormat = getUiNumberFormat(); private boolean leftAligned; private StringBuilder sb; private int horizontalDimensionWidth; @Override public void beginTable(final Crosstab<?> crosstab, final List<CrosstabDimension> horizontalDimensions, final List<CrosstabDimension> verticalDimensions) { sb = new StringBuilder(); horizontalDimensionWidth = 0; for (final CrosstabDimension dimension : horizontalDimensions) { final List<String> categories = dimension.getCategories(); for (final String category : categories) { horizontalDimensionWidth = Math.max(horizontalDimensionWidth, category.length()); } } // minimum width = 6 horizontalDimensionWidth = Math.max(horizontalDimensionWidth, 6); if (ReflectionUtils.is(crosstab.getValueClass(), Number.class)) { leftAligned = false; } else { leftAligned = true; } } @Override public void endTable() { } @Override public void beginRow() { } @Override public void endRow() { sb.append('\n'); } @Override public void horizontalHeaderCell(final String category, final CrosstabDimension dimension, final int width) { final int trailingBlanks = horizontalDimensionWidth * width - category.length(); if (leftAligned) { sb.append(category); for (int i = 0; i < trailingBlanks; i++) { sb.append(' '); } } else { for (int i = 0; i < trailingBlanks; i++) { sb.append(' '); } sb.append(category); } // separator sb.append(' '); } @Override public void verticalHeaderCell(final String category, final CrosstabDimension dimension, final int height) { sb.append(category); int dimensionWidth = getWidth(dimension); dimensionWidth = dimensionWidth - category.length(); for (int i = 0; i < dimensionWidth; i++) { sb.append(' '); } // separator sb.append(' '); } @Override public void valueCell(final Object value, final ResultProducer drillToDetailResultProducer) { boolean leftAligned = this.leftAligned; String stringValue = (value == null ? null : value.toString()); stringValue = LabelUtils.getValueLabel(stringValue); if (value instanceof Number) { leftAligned = false; if (value instanceof Double || value instanceof Float) { stringValue = decimalFormat.format(value); } } final int trailingBlanks = horizontalDimensionWidth - stringValue.length(); if (leftAligned) { sb.append(stringValue); for (int i = 0; i < trailingBlanks; i++) { sb.append(' '); } } else { for (int i = 0; i < trailingBlanks; i++) { sb.append(' '); } sb.append(stringValue); } // separator sb.append(' '); } @Override public void emptyHeader(final CrosstabDimension verticalDimension, final CrosstabDimension horizontalDimension) { final int dimensionWidth = getWidth(verticalDimension); for (int i = 0; i < dimensionWidth; i++) { sb.append(' '); } // separator sb.append(' '); } private int getWidth(final CrosstabDimension verticalDimension) { final List<String> categories = verticalDimension.getCategories(); int longestCategory = 0; for (final String category : categories) { longestCategory = Math.max(longestCategory, category.length()); } return longestCategory; } @Override public String getResult() { if (sb == null) { return ""; } return sb.toString(); } } public static NumberFormat getUiNumberFormat() { final DecimalFormatSymbols symbols = new DecimalFormatSymbols(); symbols.setDecimalSeparator('.'); final DecimalFormat format = new DecimalFormat("###.##", symbols); format.setGroupingUsed(false); format.setMaximumFractionDigits(2); return format; } @Override public String render(final CrosstabResult result) { return render(result.getCrosstab()); } public String render(final Crosstab<?> crosstab) { return new CrosstabRenderer(crosstab).render(new TextCrosstabRendererCallback()); } }