/*
 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: *
    *
  1. setFirst (always) *
  2. getDoubleValue (if data table contains number types) *
  3. setDoubleValue (if data table contains number types) *
  4. getStringValue (if data table contains String types) *
  5. setStringValue (if data table contains String types) *
  6. 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.