I’ve noticed a neat feature in Path Finder where it changes the date format used to display time stamps in the main table based on the width of the column. In rvSnoop I was allowing the user to set a preferred format as a configuration option, but this seems much better.
It turns out that this is pretty easy to achieve in Java, just use the following class:
private static class DateCellRenderer extends DefaultTableCellRenderer {
// Or load these from a user preference...
private static final DateFormat[] FORMATS = {
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"),
new SimpleDateFormat("yy-MM-dd HH:mm:ss.SSS"),
new SimpleDateFormat("MM/dd HH:mm:ss.SSS"),
new SimpleDateFormat("HH:mm:ss.SSS"),
new SimpleDateFormat("HH:mm:ss.SS"),
new SimpleDateFormat("HH:mm:ss.S"),
new SimpleDateFormat("HH:mm:ss"),
new SimpleDateFormat("HH:mm") };
private int currentWidth;
private Font currentFont;
private DateFormat currentFormat;
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
final DateFormat format = getFormat(table.getColumnModel().getColumn(col).getWidth(), table);
final String displayed = value != null ? format.format((Date) value) : "";
return super.getTableCellRendererComponent(table, displayed, isSelected, hasFocus, row, col);
}
private DateFormat getFormat(int width, JTable table) {
final Font font = table.getFont();
if (currentWidth != width) currentFormat = null;
if (currentFont == null || !currentFont.equals(font)) currentFormat = null;
if (currentFormat == null) {
currentWidth = width;
currentFont = font;
final Date date = new Date();
final FontMetrics metrics = table.getFontMetrics(font);
for (int i = 0, imax = FORMATS.length; i < imax; ++i) {
final int dateWidth = metrics.stringWidth(FORMATS[i].format(date));
if (dateWidth < width) {
currentFormat = FORMATS[i];
break;
}
}
if (currentFormat == null) {
currentFormat = FORMATS[FORMATS.length - 1];
}
}
return currentFormat;
}
}
public class DateCellRenderer extends DefaultTableCellRenderer {
private static final DateFormat[] FORMATS = {
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"),
new SimpleDateFormat("HH:mm:ss.SSS"),
new SimpleDateFormat("HH:mm:ss")};
private int currentWidth;
private Font currentFont;
private DateFormat currentFormat;
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int col) {
int w = table.getColumnModel().getColumn(col).getWidth();
DateFormat format = getFormat(w, table);
String s = value != null ? format.format((Date) value) : "";
return super.getTableCellRendererComponent(
table, s, isSelected, hasFocus, row, col);
}
private DateFormat getFormat(int width, JTable table) {
Font font = table.getFont();
if (currentWidth != width) currentFormat = null;
if (currentFont != font) currentFormat = null;
if (currentFormat == null) {
currentWidth = width;
currentFont = font;
Date date = new Date();
FontMetrics metrics = table.getFontMetrics(font);
for (int i = 0, imax = FORMATS.length; i < imax; ++i) {
DateFormat format = FORMATS[i];
String dateString = format.format(date);
int dateWidth = metrics.stringWidth(dateString);
if (dateWidth < width) {
currentFormat = format;
break;
}
}
if (currentFormat == null) {
currentFormat = FORMATS[FORMATS.length - 1];
}
}
return currentFormat;
}
}
You will need to register it with your JTable like so myTable.getColumnModel().getColumn(0).setCellRenderer(myRenderer); and away you go. You can have more or less format options by altering the static array in the class.
