/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display; import java.awt.Color; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; /** * A JTable to display rows of integers, doubles and Strings. * * @author Wolfgang Christian * @version 1.0 */ public class DataRowTable extends JTable implements ActionListener { static final Color PANEL_BACKGROUND = javax.swing.UIManager.getColor("Panel.background"); //$NON-NLS-1$ static final Color LIGHT_BLUE = new Color(204, 204, 255); protected int labelColumnWidth = 40; DataRowModel rowModel = new DataRowModel(); RowNumberRenderer indexRenderer = new RowNumberRenderer(); CellRenderer cellRenderer = new CellRenderer(); String formatPattern = "0.000"; //$NON-NLS-1$ DecimalFormat defaultFormat = new DecimalFormat(formatPattern); int refreshDelay = 0; // time in ms to delay refresh events javax.swing.Timer refreshTimer = new javax.swing.Timer(refreshDelay, this); // delay for refreshTable java.util.Dictionary<Integer, DecimalFormat> formats = new java.util.Hashtable<Integer, DecimalFormat>(); /** * Constructor DataRowTable */ public DataRowTable() { init(); } /** * Initializes the table. */ protected void init() { refreshTimer.setRepeats(false); refreshTimer.setCoalesce(true); setModel(rowModel); setColumnSelectionAllowed(true); setGridColor(Color.blue); setSelectionBackground(LIGHT_BLUE); setSelectionForeground(Color.red); // foreground color for selected cells setColumnModel(new DataTableColumnModel()); setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); setColumnSelectionAllowed(true); rowModel.addTableModelListener(new TableModelListener() { public void tableChanged(TableModelEvent e) { // forward the table model event to property change listeners DataRowTable.this.firePropertyChange("cell", null, e); //$NON-NLS-1$ } }); setDefaultRenderer(Object.class, cellRenderer); getTableHeader().setForeground(Color.blue); // set text color getTableHeader().setReorderingAllowed(true); getTableHeader().setDefaultRenderer(new HeaderRenderer()); setAutoResizeMode(JTable.AUTO_RESIZE_OFF); int width = 24; String name; TableColumn column; if(getColumnCount()>0) { // set width of column 0 (row index) name = getColumnName(0); column = getColumn(name); column.setMinWidth(width); column.setMaxWidth(2*width); column.setWidth(width); } // set width of other columns width = 60; for(int i = 1, n = getColumnCount(); i<n; i++) { name = getColumnName(i); column = getColumn(name); column.setMinWidth(width); column.setMaxWidth(3*width); column.setWidth(width); } } /** * Sets the <code>Timer</code>'s initial time delay (in milliseconds) * to wait after the timer is started * before firing the first event. * @param delay */ public void setRefreshDelay(int delay) { if(delay>0) { refreshTimer.setDelay(delay); refreshTimer.setInitialDelay(delay); } else if(delay<=0) { refreshTimer.stop(); } refreshDelay = delay; } public void clearFormats() { formats = new java.util.Hashtable<Integer, DecimalFormat>(); } /** * Sets the default numeric display format pattern. * @param defaultFormat */ public void setNumericFormat(String str) { if((str!=null)&&!str.equals(formatPattern)) { // format has changed formatPattern = str; defaultFormat = new DecimalFormat(str); refreshTable(); } } /** * Sets the column decimal format. * * @param column the column index * @param format the format */ public void setColumnFormat(int column, String format) { DecimalFormat f = new DecimalFormat(format); DecimalFormat val = formats.get(column); if((val!=null)&&val.equals(f)) { return; // nothing changed } formats.put(column, f); refreshTable(); } /** * Clears data from this table. Column names and format patterns are not affected. */ public synchronized void clearData() { rowModel.rowList.clear(); rowModel.colCount = 0; refreshTable(); } /** * Clears data, column names, and format patterns. */ public synchronized void clear() { rowModel.rowList.clear(); rowModel.colNames.clear(); rowModel.colCount = 0; formats = new java.util.Hashtable<Integer, DecimalFormat>(); refreshTable(); } /** * Sets the stride between rows. * * @param tableModel * @param stride */ public void setStride(int stride) { stride = Math.max(1, stride); if(rowModel.stride==stride) { return; // nothing changed } rowModel.setStride(stride); refreshTable(); } /** * Refresh the data in the DataTable, as well as other changes to the table, * such as row number visibility. Changes to the TableModels displayed in the * table will not be visible until this method is called. */ public void refreshTable() { if(refreshDelay>0) { refreshTimer.start(); } else { Runnable doRefreshTable = new Runnable() { public synchronized void run() { tableChanged(new TableModelEvent(getModel(), TableModelEvent.HEADER_ROW)); } }; if(SwingUtilities.isEventDispatchThread()) { doRefreshTable.run(); } else { SwingUtilities.invokeLater(doRefreshTable); } } } /** * Returns the renderer for a cell specified by row and column. * * @param row the row number * @param column the column number * @return the cell renderer */ public TableCellRenderer getCellRenderer(int row, int column) { int i = convertColumnIndexToModel(column); if((i==0)&&rowModel.rowNumberVisible) { return indexRenderer; } return cellRenderer; //return getDefaultRenderer(getColumnClass(column)); } /** * Performs the action for the refresh timer by refreshing the data in the DataTable. * * @param evt */ public void actionPerformed(ActionEvent evt) { tableChanged(new TableModelEvent(getModel(), TableModelEvent.HEADER_ROW)); } private class CellRenderer extends DefaultTableCellRenderer { /** * PrecisionRenderer constructor * */ public CellRenderer() { super(); setHorizontalAlignment(SwingConstants.RIGHT); setBorder(new CellBorder(new Color(224, 224, 224))); setBackground(Color.WHITE); } /** * returns a JLabel that is highlighted if the row is selected. * * @param table * @param value * @param isSelected * @param hasFocus * @param row * @param column * @return */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if(!rowModel.rowNumberVisible) { column++; } DecimalFormat f = formats.get(column); if(f==null) { f = defaultFormat; } if(value==null) { setText(""); //$NON-NLS-1$ } else if(value instanceof String) { setText((String) value); } else if(f==null) { setText(value.toString()); } else { try { setText(f.format(value)); } catch(IllegalArgumentException ex) { setText(value.toString()); } } return this; } } private class HeaderRenderer extends RowNumberRenderer { /** * Constructor HeaderRenderer */ public HeaderRenderer() { super(); setHorizontalAlignment(SwingConstants.CENTER); setForeground(Color.BLUE); setBorder(javax.swing.BorderFactory.createLineBorder(new Color(224, 224, 224))); } } private static class RowNumberRenderer extends JLabel implements TableCellRenderer { /** * RowNumberRenderer constructor * */ public RowNumberRenderer() { super(); setHorizontalAlignment(SwingConstants.RIGHT); setOpaque(true); // make background visible. setForeground(Color.BLACK); setBackground(PANEL_BACKGROUND); setBorder(new CellBorder(new Color(224, 224, 224))); } /** * returns a JLabel that is highlighted if the row is selected. * * @param table * @param value * @param isSelected * @param hasFocus * @param row * @param column * @return */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if(table.isRowSelected(row)) { int[] i = table.getSelectedColumns(); if((i.length==1)&&(table.convertColumnIndexToModel(i[0])==0)) { setBackground(PANEL_BACKGROUND); } else { setBackground(Color.gray); } } else { setBackground(PANEL_BACKGROUND); } if(value==null){ // added by W. Christian setText("???"); //$NON-NLS-1$ }else{ setText(value.toString()); } return this; } } private class DataTableColumnModel extends DefaultTableColumnModel { /** * Method getColumn * * @param columnIndex * @return */ public TableColumn getColumn(int columnIndex) { TableColumn tableColumn; try { tableColumn = super.getColumn(columnIndex); } catch(Exception ex) { // return an empty column if the columnIndex is not valid. return new TableColumn(); } String headerValue = (String) tableColumn.getHeaderValue(); if(headerValue==null) { return tableColumn; } else if(headerValue.equals("row")) { //$NON-NLS-1$ tableColumn.setMaxWidth(labelColumnWidth); tableColumn.setMinWidth(labelColumnWidth); tableColumn.setResizable(true); } return tableColumn; } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */