TableFormatter.java
package org.djunits.formatter;
import java.util.Locale;
import org.djunits.vecmat.table.AbsQuantityTable;
import org.djunits.vecmat.table.QuantityTable;
/**
* TableFormatter formats a table as a String, using the settings of the {@link TableFormatContext}. The
* {@link TableFormatContext} is filled by setting properties of the {@link TableFormatContext}. Note that there is no guarantee
* that the format can always be honored. As an example, when the required width is too small to fit the answer, the output will
* show the correct result, but violate the width setting.
* <p>
* Copyright (c) 2026-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
* distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
* @author Alexander Verbraeck
*/
public class TableFormatter extends Formatter<TableFormatContext>
{
/**
* @param table the table to format
* @param ctx the format context
*/
TableFormatter(final QuantityTable<?> table, final TableFormatContext ctx)
{
super(table, ctx);
}
/**
* Return the value as a table (or table).
* @return the value as a table (or table)
*/
QuantityTable<?> table()
{
return (QuantityTable<?>) this.value;
}
/**
* Format a table according to a number of table format settings. Note that this method might not be thread-safe for setting
* the default Locale. If another thread changes the Locale while formatting, outcomes could vary.
* @param table the table to format
* @param tableFormat the format to apply to the table
* @return a String with a formatted table, matching the table format settings as closely as possible
*/
public static String format(final QuantityTable<?> table, final TableFormat tableFormat)
{
TableFormatContext ctx = tableFormat.ctx;
Locale savedLocale = Locale.getDefault();
try
{
savedLocale = saveLocale(ctx.locale);
return new TableFormatter(table, ctx).format();
}
finally
{
restoreLocale(savedLocale);
}
}
/**
* Format an absolute table according to a number of table format settings. Note that this method might not be thread-safe
* for setting the default Locale. If another thread changes the Locale while formatting, outcomes could vary.
* @param absTable the absolute table to format
* @param tableFormat the format to apply to the table
* @return a String with a formatted table, matching the table format settings as closely as possible
*/
public static String format(final AbsQuantityTable<?, ?> absTable, final TableFormat tableFormat)
{
TableFormatContext ctx = tableFormat.ctx;
Locale savedLocale = Locale.getDefault();
try
{
savedLocale = saveLocale(ctx.locale);
return new TableFormatter(absTable.getRelativeVecMat(), ctx).format()
+ formatReference(ctx, absTable.getReference());
}
finally
{
restoreLocale(savedLocale);
}
}
/**
* Return the table, formatted according to the context settings.
* @return the formatted table
*/
@SuppressWarnings("checkstyle:needbraces")
@Override
String format()
{
formatUnit();
StringBuilder s = new StringBuilder();
s.append(this.ctx.tablePrefix);
for (int r = 0; r < table().rows(); r++)
{
if (r == 0)
s.append(this.ctx.firstRowStartSymbol);
else if (r == table().rows() - 1)
s.append(this.ctx.lastRowStartSymbol);
else
s.append(this.ctx.middleRowStartSymbol);
for (int c = 0; c < table().cols(); c++)
{
if (c > 0)
s.append(this.ctx.colSeparatorSymbol);
double si = table().si(r, c);
double value = this.useSi ? si : this.unit.getScale().fromIdentityScale(si);
s.append(formatValue(value));
}
if (r == 0)
s.append(this.ctx.firstRowEndSymbol);
else if (r == table().rows() - 1)
s.append(this.ctx.lastRowEndSymbol);
else
s.append(this.ctx.middleRowEndSymbol);
}
s.append(this.ctx.tablePostfix);
s.append(this.ctx.unitPrefix);
s.append(this.unitStr);
s.append(this.ctx.unitPostfix);
return s.toString();
}
}