/*
This file is part of the software framework JStatCom,
a library for building applications for data based analysis.
Copyright (C) 2000-2005 Markus Kraetzig
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This library 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 library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
*/
package com.jstatcom.table;
import java.awt.Color;
import java.awt.Component;
import java.text.NumberFormat;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import com.jstatcom.component.NumberFormatTypes;
import com.jstatcom.equation.CoeffTable;
import com.jstatcom.equation.VarNamesVector;
import com.jstatcom.model.JSCNArray;
/**
* The class defines different JSCCellRenderers for the JSCAbstractDataTable,
* which can be used in different modeling contexts, for example to display coefficients matrizes or
* subset matrizes. It is possible to extend this enumeration to provide special
* renderers for different contexts.
*
* The class implements the typesave enum pattern (Joshua Bloch, "Effective Java", Item 21).
* If you compare JSCCellRendererTypes, always use the == operator. This is
* save, because they are Singletons (Gamma et al., 1995).
*
* @author A.Benkwitz, Markus Kraetzig
*/
public class JSCCellRendererTypes extends JLabel implements TableCellRenderer {
private static final String space = " ";
private final NumberFormat numberFormat =
NumberFormatTypes.DEFAULT.getInstance();
private static final Double doubleNAN = new Double(Double.NaN);
/**
* The name of the type.
*/
private final String name;
/**
* Default TableCellRenderer. It displays doubles as they appear with
* a given precision set by the underlying table,
* using the default number format.
*/
public static final JSCCellRendererTypes DEFAULT =
new JSCCellRendererTypes("DEFAULT") {
protected void setFirst(
JTable table,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
setHorizontalAlignment(RIGHT);
}
};
/**
* TableCellRenderer with scientific notation, for example 1.23E-2.
* It also takes the precision into account.
*/
public static final JSCCellRendererTypes SCIENTIFIC =
new JSCCellRendererTypes("SCIENTIFIC") {
private final NumberFormat scienceFormat =
NumberFormatTypes.SCIENTIFIC.getInstance();
protected void setFirst(
JTable table,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
setHorizontalAlignment(RIGHT);
}
protected void setDoubleValue(double value, NumberDisplayTable table) {
if (new Double(value).equals(doubleNAN)) {
setText(value + space);
} else {
if (table != null) {
scienceFormat.setMaximumFractionDigits(
table.getPrecision());
scienceFormat.setMinimumFractionDigits(
table.getPrecision());
}
setText(scienceFormat.format(value) + space);
}
}
};
/**
* Default TableCellRenderer for coefficients. It displays doubles as they appear with
* a given precision set by the underlying table. If an element is restricted
* by the underlying restricion matrix, it is displayed as "---". This is also true for values
* that are exactly 0.
*/
public static final JSCCellRendererTypes COEFF_DEFAULT =
new JSCCellRendererTypes("COEFF_DEFAULT") {
private final NumberFormat numberFormat =
NumberFormatTypes.DEFAULT.getInstance();
protected double getDoubleValue(
JSCNArrayTable table,
int row,
int col) {
int convertCol = table.convertColumnIndexToModel(col);
if (isSubsetRes(table, row, convertCol))
return Double.NaN;
return table.getJSCNArray().doubleAt(row, convertCol);
}
//
protected void setDoubleValue(double value, NumberDisplayTable table) {
if (new Double(value).equals(doubleNAN) || value == 0)
setText("---" + space);
else {
if (table != null) {
numberFormat.setMaximumFractionDigits(table.getPrecision());
numberFormat.setMinimumFractionDigits(table.getPrecision());
}
setText(numberFormat.format(value) + space);
}
}
};
/**
* Scientific TableCellRenderer for coefficients. It displays doubles as they appear with
* a given precision set by the underlying table. If an element is restricted
* by the underlying restricion matrix, it is displayed as "---"
*/
public static final JSCCellRendererTypes COEFF_SCIENTIFIC =
new JSCCellRendererTypes("COEFF_SCIENTIFIC") {
private final NumberFormat numberFormat =
NumberFormatTypes.SCIENTIFIC.getInstance();
//
protected double getDoubleValue(
JSCNArrayTable table,
int row,
int col) {
int convertCol = table.convertColumnIndexToModel(col);
if (isSubsetRes(table, row, convertCol))
return Double.NaN;
return table.getJSCNArray().doubleAt(row, convertCol);
}
//
protected void setDoubleValue(double value, NumberDisplayTable table) {
if (new Double(value).equals(doubleNAN) || value == 0)
setText("---" + space);
else {
if (table != null) {
numberFormat.setMaximumFractionDigits(table.getPrecision());
numberFormat.setMinimumFractionDigits(table.getPrecision());
}
setText(numberFormat.format(value) + space);
}
}
};
/**
* A TableCellRenderer for the subset matrizes. It displays "0" for 0,
* "*" for 1 and "---" for all other values.
* If a subset restriction is set in the coefficients table,
* the corresponding element is set to Double.NaN and displayed as "---".
*/
public static final JSCCellRendererTypes SUBSET_01 =
new JSCCellRendererTypes("SUBSET_01") {
{
setHorizontalAlignment(CENTER);
}
/**
* Check whether corresponding element in restriction matrix
* is set to 0. If yes, set it to Double.NaN.
*/
protected double getDoubleValue(
JSCNArrayTable table,
int row,
int col) {
/**
* Column convert is done.
*/
int convertCol = table.convertColumnIndexToModel(col);
if (isSubsetRes(table, row, convertCol))
return Double.NaN;
return table.getJSCNArray().doubleAt(row, convertCol);
}
//
protected void setDoubleValue(double d, NumberDisplayTable table) {
if (d == 0)
setText("0");
else if (d == 1)
setText("*");
else
setText("---");
}
};
/**
* A TableCellRenderer for the non editable subset matrizes
* with a gray background. It displays "0" for 0,
* "*" for 1 and "---" for all other values.
* If a subset restriction is set in the coefficients table,
* the corresponding element is set to Double.NaN and displayed as "---".
*/
public static final JSCCellRendererTypes SUBSET_01_GRAY =
new JSCCellRendererTypes("SUBSET_01_GRAY") {
{
setHorizontalAlignment(CENTER);
}
/**
* Check whether corresponding element in restriction matrix
* is set to 0. If yes, set it to Double.NaN.
*/
protected double getDoubleValue(
JSCNArrayTable table,
int row,
int col) {
/**
* Column convert is done.
*/
int convertCol = table.convertColumnIndexToModel(col);
if (isSubsetRes(table, row, convertCol))
return Double.NaN;
return table.getJSCNArray().doubleAt(row, convertCol);
}
//
protected void setDoubleValue(double d, NumberDisplayTable table) {
setBackground(Color.lightGray);
if (d == 0)
setText("0");
else if (d == 1)
setText("*");
else
setText("---");
}
};
/**
* A TableCellRenderer for subset matrizes. It displays "0" for 0,
* "*" for 1 and "!" for 2. All other values are displayed as "---".
* If a subset restriction is set in the underlying coefficients table,
* the corresponding element is set to Double.NaN and displayed as "---".
*/
public static final JSCCellRendererTypes SUBSET_012 =
new JSCCellRendererTypes("SUBSET_012") {
{
setHorizontalAlignment(CENTER);
}
/**
* Check whether corresponding element in restriction matrix
* is set to 0. If yes, set it to Double.NaN.
*/
protected double getDoubleValue(
JSCNArrayTable table,
int row,
int col) {
int convertCol = table.convertColumnIndexToModel(col);
if (isSubsetRes(table, row, convertCol))
return Double.NaN;
return table.getJSCNArray().doubleAt(row, convertCol);
}
//
protected void setDoubleValue(double d, NumberDisplayTable table) {
if (d == 0)
setText("0");
else if (d == 1)
setText("*");
else if (d == 2)
setText("!");
else
setText("---");
}
};
/**
* A TableCellRenderer for the special subset matrizes. It displays "0" for 0,
* "*" for 1 and "---" for all other values. The diagonal elements are rendered
* with a gray background, because they are usually not editable.
* If a subset restriction is set in the coefficients table,
* the corresponding element is set to Double.NaN and displayed as "---".
* This renderer might be used for the matrix of structural coefficients.
*/
public static final JSCCellRendererTypes DIAGONAL_01 =
new JSCCellRendererTypes("DIAGONAL_01") {
boolean onDiagonal = false;
private final NumberFormat numberFormat =
NumberFormatTypes.DEFAULT.getInstance();
{
setHorizontalAlignment(CENTER);
numberFormat.setMaximumFractionDigits(0);
numberFormat.setMinimumFractionDigits(0);
}
protected void setFirst(
JTable table,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
onDiagonal = row == col;
}
/**
* Checks whether corresponding element in restriction matrix
* is set to 0. If yes, set it to Double.NaN. Also set the
* ondiagonal property, which means that elements of the
* diagonal are displayed "as is", especially 1 is displayed as
* "1". Other elements are displayed: 0 "0" : 1 "*" : other "---".
* The diagonal cells are displayed with bachground Color.lightGray.
*/
protected double getDoubleValue(
JSCNArrayTable table,
int row,
int col) {
int convertCol = table.convertColumnIndexToModel(col);
if (isSubsetRes(table, row, convertCol))
return Double.NaN;
return table.getJSCNArray().doubleAt(row, convertCol);
}
//
protected void setDoubleValue(double d, NumberDisplayTable table) {
if (onDiagonal) {
setBackground(Color.lightGray);
setText(numberFormat.format(d));
return;
}
if (d == 0)
setText("0");
else if (d == 1)
setText("*");
else
setText("---");
}
};
/**
* Equation String TableCellRenderer. It is used as a left hand side
* equation description.
*/
public static final JSCCellRendererTypes EQUATION_NAMES =
new JSCCellRendererTypes("EQUATION_NAMES") {
{
setHorizontalAlignment(LEFT);
}
public void setStringValue(String arg) {
setText(space + "\"" + arg + "\" - Equation" + space);
}
};
/**
* String TableCellRenderer for variable names. It displays an index
* if it is set for a VarNamesVector and isShowingIndex
* is true.
*/
public static final JSCCellRendererTypes VARIABLE_NAMES =
new JSCCellRendererTypes("VARIABLE_NAMES") {
private VarNamesVector namesVector = null;
{
setHorizontalAlignment(RIGHT);
}
protected void setStringValue(String text) {
if (text == null) {
setText(space + "null" + space);
return;
}
if (namesVector == null) {
setText(space + text + space);
return;
}
if (namesVector.isShowingTimeIndex()
&& !text.equals(VarNamesVector.VARIABLE_NAME_CONSTANT)) {
text = text + namesVector.getIndexString();
}
setText(space + text + space);
}
protected void setFirst(
JTable table,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
if (table instanceof VarNamesVector)
namesVector = (VarNamesVector) table;
else
namesVector = null;
}
};
/**
* A TableCellRenderer for the A and B matrizes of an SVAR model.
* It displays "0" for 0, "*" for -INF, "1" for 1, "-1" for -1 and all other values "as is".
* The diagonal elements are rendered with a gray background, because they are usually not editable.
*/
public static final JSCCellRendererTypes DIAG_01M1NEGINF =
new JSCCellRendererTypes("DIAG_01M1NEGINF") {
boolean onDiagonal = false;
protected void setFirst(
JTable table,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
onDiagonal = row == col;
}
protected void setDoubleValue(double d, NumberDisplayTable table) {
setHorizontalAlignment(CENTER);
if (onDiagonal)
setBackground(Color.lightGray);
if (d == 0)
setText("0");
else if (d == 1)
setText("1");
else if (d == -1)
setText("-1");
else
// Unrestricted
if (d == Double.NEGATIVE_INFINITY)
setText("*");
else {
setHorizontalAlignment(RIGHT);
super.setDoubleValue(d, table);
}
}
};
/**
* A TableCellRenderer for the A and B matrizes of an SVAR model.
* It displays "0" for 0, "*" for -INF, "1" for 1, "-1" for -1 and all other values "as is".
*/
public static final JSCCellRendererTypes SUBSET_01M1NEGINF =
new JSCCellRendererTypes("SUBSET_01M1NEGINF") {
protected void setDoubleValue(double d, NumberDisplayTable table) {
setHorizontalAlignment(CENTER);
if (d == 0)
setText("0");
else if (d == 1)
setText("1");
else if (d == -1)
setText("-1");
else
// Unrestricted
if (d == Double.NEGATIVE_INFINITY)
setText("*");
else {
setHorizontalAlignment(RIGHT);
super.setDoubleValue(d, table);
}
}
};
/**
* JSCPopupTypes constructor with a descriptive name.
* It sets the alignment to JLabel.RIGHT
*
* @param name descriptive name
*/
protected JSCCellRendererTypes(String name) {
super();
this.name = name;
setOpaque(true);
setHorizontalAlignment(RIGHT);
}
/**
* Override prevention method to enforce
* a.equals(b) if and only if a==b.
*
* @param o object to compare with
* @return true if equal, false otherwise
*/
public final boolean equals(Object o) {
return super.equals(o);
}
/**
* Gets a double value from a data table.
* Subclasses can overwrite this method to provide special
* values, for example if a subset restriction is present for the
* respective element. This default implementation just gets
* the value from the position in the table.
*
* @param table the data table to retrieve the value from
* @param row index for row
* @param col index for column
* @return the retrieved double
*/
protected double getDoubleValue(JSCNArrayTable table, int row, int col) {
int convertCol = table.convertColumnIndexToModel(col);
return table.getJSCNArray().doubleAt(row, convertCol);
}
/**
* Gets the name of this type.
*
* @return a descriptive name
*/
public final String getName() {
return name;
}
/**
* Gets a String value from a data table.
* Subclasses can overwrite this method to provide special
* values. This default implementation just gets
* the value from the position in the table.
*
* @param table the data table to retrieve the value from
* @param row index for row
* @param col index for column
* @return the retrieved String
*/
protected String getStringValue(JSCSArrayTable table, int row, int col) {
int convertCol = table.convertColumnIndexToModel(col);
if (table.isDisplayTransposed())
return table.getJSCSArray().stringAt(convertCol, row);
return table.getJSCSArray().stringAt(row, convertCol);
}
/**
* Defines how the cell is painted. It is a template method here,
* because the set and get methods can be
* redefined by subclasses of JSCDataTableRendererTypes
* without changing the general structure of the algorithm.
* The ordering of calls is the following:
*
* setFirst (always)
* getDoubleValue (if data table contains number types)
* setDoubleValue (if data table contains number types)
* getStringValue (if data table contains String types)
* setStringValue (if data table contains String types)
* setValue (if data table contains other types)
*
*
* @param table the table to render
* @param value the value to display
* @param isSelected true if cell is selected
* @param hasFocus true if cell has focus
* @param row index for row
* @param col index for column
* @return the assembled renderer component
*/
public final Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
setFirst(table, isSelected, hasFocus, row, col);
if (isEnabled() != table.isEnabled())
setEnabled(table.isEnabled());
if (isSelected) {
super.setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
super.setForeground(table.getForeground());
super.setBackground(table.getBackground());
}
setFont(table.getFont());
//
if (table instanceof JSCAbstractDataTable) {
JSCAbstractDataTable dataTable = (JSCAbstractDataTable) table;
if (dataTable instanceof JSCNArrayTable) {
col = col % dataTable.getColumnCount();
JSCNArrayTable nArrayTable = (JSCNArrayTable) dataTable;
double d = getDoubleValue(nArrayTable, row, col);
setDoubleValue(d, nArrayTable);
} else if (dataTable instanceof JSCSArrayTable) {
JSCSArrayTable sArrayTable = (JSCSArrayTable) dataTable;
String s = getStringValue(sArrayTable, row, col);
setStringValue(s);
} else {
setValue(dataTable.getValueAt(row, col), dataTable);
}
} else {
setValue(table.getValueAt(row, col), table);
}
//
return this;
}
/**
* Override prevention method invokes super method.
*
* @return hash code
*/
public final int hashCode() {
return super.hashCode();
}
/**
* Checks, whether there is a subset restriction at
* the given position (row, col) in the subset restriction
* matrix. The subset matrix must be referenced from the data table
* implementation, for example
* com.jstatcom.equation.CoeffTable.
*
* @param table the data table with a possible reference to a subset matrix
* @param row index for row
* @param col index for column
* @return true if the corresponding subset matrix exists and
* the element at (row, col) is set to restricted
* @see com.jstatcom.equation.CoeffTable
*/
protected boolean isSubsetRes(JSCNArrayTable table, int row, int col) {
if (!(table instanceof CoeffTable))
return false;
JSCNArray subsetRes = ((CoeffTable) table).getJSCNArraySubsetRes();
if (subsetRes != null) {
// Check for restriction. If 0 then element is restricted.
if (row < subsetRes.rows() && col < subsetRes.cols())
return subsetRes.intAt(row, col) == 0;
}
return false;
}
/**
* Sets how a double value is printed as text.
*
* @param value the value to print
* @param table an instance of NumberDisplayTable, which
* allows to set a certain CellRenderer
* an a precision to render value
*/
protected void setDoubleValue(double value, NumberDisplayTable table) {
if (new Double(value).equals(doubleNAN)) {
setText(value + space);
} else {
if (table != null) {
numberFormat.setMaximumFractionDigits(table.getPrecision());
numberFormat.setMinimumFractionDigits(table.getPrecision());
}
setText(numberFormat.format(value) + space);
}
}
/**
* This is the first method called by getTableCellRendererComponent.
* Override it, if you want to set certain properties before any other
* methods are called. This could be used to change the alignment or to
* initialize certain fields.
*
* @param table the table to render
* @param isSelected true if cell is selected
* @param hasFocus true if cell has focus
* @param row index for row
* @param col index for column
*/
@SuppressWarnings("unused")
protected void setFirst(
JTable table,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
}
/**
* Sets how a String value is printed as text.
*
* @param value the value to print
*/
protected void setStringValue(String value) {
setText(value == null ? "" : space + value + space);
}
/**
* Sets how a general Object value is printed as text.
* This does usually depend on the type of the value
* to print.
*
* @param value the value to print
* @param table an instance of JTable, which
* allows to set a certain CellRenderer
* an a precision to render value
*/
private void setValue(Object value, JTable table) {
if (table instanceof NumberDisplayTable)
setDoubleValue(
((Double) value).doubleValue(),
(NumberDisplayTable) table);
else {
if (value != null)
setStringValue(value.toString() + space);
else
setText("");
}
}
/**
* Gets a string representing this type, do not use for comparisons.
*
* @return string representation
*/
public final String toString() {
return name;
}
}
Ads help maintain this website.