/*
* 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 javax.swing.table.AbstractTableModel;
/**
* A table model for a 1D and 2D ArrayTable.
*
* Column names, column locks, and transposed property added in version 1.1.
*
* @author Douglas Brown
* @author Wolfgang Christian
* @version 1.1
*/
public class ArrayTableModel extends AbstractTableModel {
double[] doubleArray1;
double[][] doubleArray2;
int[] intArray1;
int[][] intArray2;
String[] stringArray1;
String[][] stringArray2;
boolean[] booleanArray1;
boolean[][] booleanArray2;
boolean editable = false;
String[] columnNames;
boolean showRowNumber = true;
int firstRow = 0, firstCol = 0;
boolean transposed = false;
java.util.Dictionary<Integer, Boolean> lockedColumns = new java.util.Hashtable<Integer, Boolean>();
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(int[] array) {
intArray1 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(int[][] array) {
intArray2 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(double[] array) {
doubleArray1 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(double[][] array) {
doubleArray2 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(String[] array) {
stringArray1 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(String[][] array) {
stringArray2 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(boolean[] array) {
booleanArray1 = array;
}
/**
* Constructor ArrayTableModel
* @param array
*/
public ArrayTableModel(boolean[][] array) {
booleanArray2 = array;
}
/**
* Allows changing the array with minimal changes
* @param arrayObj
*/
public void setArray(Object arrayObj) {
if(arrayObj instanceof double[]) {
doubleArray1 = (double[]) arrayObj;
} else if(arrayObj instanceof double[][]) {
doubleArray2 = (double[][]) arrayObj;
} else if(arrayObj instanceof int[]) {
intArray1 = (int[]) arrayObj;
} else if(arrayObj instanceof int[][]) {
intArray2 = (int[][]) arrayObj;
} else if(arrayObj instanceof String[]) {
stringArray1 = (String[]) arrayObj;
} else if(arrayObj instanceof String[][]) {
stringArray2 = (String[][]) arrayObj;
} else if(arrayObj instanceof boolean[]) {
booleanArray1 = (boolean[]) arrayObj;
} else if(arrayObj instanceof boolean[][]) {
booleanArray2 = (boolean[][]) arrayObj;
}
}
/**
* Sets the column's lock flag. Returns true if the column's lock changes.
*
* @param column int
* @param locked boolean
* @return true if change occurred
*/
public boolean setColumnLock(int columnIndex, boolean locked) {
Boolean val = lockedColumns.get(columnIndex);
if((val!=null)&&(locked==val)) {
return false; // nothing changed
}
lockedColumns.put(columnIndex, locked);
return true;
}
/**
* Sets the lock flag for multiple columns. Previously set locks are cleared.
*
* @param locked boolean array
* @return true if change occurred
*/
public boolean setColumnLocks(boolean[] locked) {
boolean change = false;
if(lockedColumns.size()!=locked.length) {
change = true;
} else { // lengths are correct so check values
for(int i = 0, n = locked.length; i<n; i++) {
Boolean val = lockedColumns.get(i);
if(!Boolean.valueOf(locked[i]).equals(val)) {
change = true;
break;
}
}
}
if(!change) {
return false;
}
// locked columns have changed; clear old values and add new values
((java.util.Hashtable<Integer, Boolean>) lockedColumns).clear();
for(int i = 0, n = locked.length; i<n; i++) {
lockedColumns.put(i, locked[i]);
}
return true;
}
/**
* Sets the first row's index.
*
* @param index
*/
public void setFirstRowIndex(int index) {
firstRow = index;
}
/**
* Sets the first column's index.
*
* @param index
*/
public void setFirstColIndex(int index) {
firstRow = index;
}
/**
* Sets the display row number flag. Table displays row number.
*
* @param vis <code>true<\code> if table display row number
*/
public void setRowNumberVisible(boolean vis) {
showRowNumber = vis;
}
/**
* Sets the transposed property for the array.
* A transposed array switches its row and column values in the display.
*
* @param transposed
*/
public void setTransposed(boolean transposed) {
this.transposed = transposed;
}
/**
* Returns true of the table's row and column values are interchanged.
* @return
*/
public boolean isTransposed() {
return transposed;
}
/**
* Sets the editable property.
*
* @param editable true allows editing of the cell values that are not locked.
*/
public void setEditable(boolean editable) {
this.editable = editable;
}
/**
* Gets the number of columns.
*
* @return the column count
*/
public int getColumnCount() {
if(getArrayRowCount()==0) {
return 0; // don't show columns if there aren't any rows
}
int offset = showRowNumber // row numbers add a column
? 1 : 0;
if(transposed) {
return getArrayRowCount()+offset;
}
return getArrayColumnCount()+offset;
}
/**
* Gets the number of columns in the matrix.
* The second index is the column index in 2D arrays.
*
* @return the column count
*/
int getArrayColumnCount() {
if((intArray1!=null)||(doubleArray1!=null)||(stringArray1!=null)||(booleanArray1!=null)) {
return 1;
}
if(intArray2!=null) {
return intArray2[0].length;
}
if(doubleArray2!=null) {
return doubleArray2[0].length;
}
if(stringArray2!=null) {
return stringArray2[0].length;
}
if(booleanArray2!=null) {
return booleanArray2[0].length;
}
return 0;
}
/**
* Sets columns names. Returns true if the table has changed.
* @param names
* @return changed
*/
public boolean setColumnNames(String[] names) {
if((names==null)&&(columnNames==null)) {
return false; // neither array exists but there is no change
}
if(names!=null) {
names = names.clone(); // clone the array as the TeX parser may change string values
}
boolean changed = false;
if((names!=null)&&(columnNames!=null)&&(columnNames.length==names.length)) { // arrays exist and have same length
for(int i = 0, n = names.length; i<n; i++) {
names[i] = TeXParser.parseTeX(names[i]); // convert TeX within each string
if(!names[i].equals(columnNames[i])) { // check each name for a change
changed = true; // the i-th column name has changed
}
}
} else { // arrays have different lengths
changed = true;
if(names!=null) {
for(int i = 0, n = names.length; i<n; i++) {
names[i] = TeXParser.parseTeX(names[i]); // convert TeX within each string
}
}
}
columnNames = names;
return changed;
}
/**
* Gets the name of the specified column.
*
* @param column the column index
* @return the column name
*/
public String getColumnName(int column) {
if(!showRowNumber) {
column++;
}
if((columnNames!=null)&&(column<columnNames.length)) {
return columnNames[column];
}
if(column==0) {
return ""; //$NON-NLS-1$
}
if((intArray1!=null)||(doubleArray1!=null)||(stringArray1!=null)||(booleanArray1!=null)) {
return "value"; //$NON-NLS-1$
}
return ""+(column-1+firstCol); //$NON-NLS-1$
}
/**
* Gets the number of rows.
*
* @return the row count
*/
public int getRowCount() {
if(transposed) {
return getArrayColumnCount();
}
return getArrayRowCount();
}
/**
* Gets the number of rows in the array.
* The first index is the row index.
*
* @return the row count
*/
int getArrayRowCount() {
if(intArray1!=null) {
return intArray1.length;
}
if(intArray2!=null) {
return intArray2.length;
}
if(doubleArray1!=null) {
return doubleArray1.length;
}
if(doubleArray2!=null) {
return doubleArray2.length;
}
if(stringArray1!=null) {
return stringArray1.length;
}
if(stringArray2!=null) {
return stringArray2.length;
}
if(booleanArray1!=null) {
return booleanArray1.length;
}
if(booleanArray2!=null) {
return booleanArray2.length;
}
return 0;
}
/**
* Gets the value at the given cell.
*
* @param row the row index
* @param column the column index
* @return the value
*/
public Object getValueAt(int row, int column) {
if(showRowNumber&&(column==0)) {
return new Integer(row+firstRow);
}
int offset = showRowNumber ? 1 : 0;
if(transposed) {
int temp = row;
row = column-offset;
column = temp;
}
if(intArray1!=null) {
return new Integer(intArray1[row]);
}
if(intArray2!=null) {
int col = transposed ? column : column-offset;
if((row>intArray2.length-1)||(col>intArray2[row].length-1)||(col<0)) {
return null;
}
return new Integer(intArray2[row][col]);
}
if(doubleArray1!=null) {
return new Double(doubleArray1[row]);
}
if(doubleArray2!=null) {
int col = transposed ? column : column-offset;
if((row>doubleArray2.length-1)||(col>doubleArray2[row].length-1)||(col<0)) {
return null;
}
return new Double(doubleArray2[row][col]);
}
if(stringArray1!=null) {
return stringArray1[row];
}
if(stringArray2!=null) {
int col = transposed ? column : column-offset;
if((row>stringArray2.length-1)||(col>stringArray2[row].length-1)||(col<0)) {
return null;
}
return stringArray2[row][col];
}
if(booleanArray1!=null) {
return new Boolean(booleanArray1[row]);
}
if(booleanArray2!=null) {
int col = transposed ? column : column-offset;
if((row>booleanArray2.length-1)||(col>booleanArray2[row].length-1)||(col<0)) {
return null;
}
return new Boolean(booleanArray2[row][col]);
}
return null;
}
/**
* Sets the value at the given cell.
*
* @param value the value
* @param row the row index
* @param col the column index
*/
public void setValueAt(Object value, int row, int col) {
int offset = showRowNumber ? 1 : 0; // added by WC
if(transposed) {
int temp = row;
row = col-offset;
col = temp;
}
try {
if(value instanceof String) {
String val = (String) value;
col = transposed ? col : col-offset; // added by WC
if(intArray1!=null) {
intArray1[row] = Integer.parseInt(val);
} else if(intArray2!=null) {
intArray2[row][col] = Integer.parseInt(val);
} else if(doubleArray1!=null) {
doubleArray1[row] = Double.parseDouble(val);
} else if(doubleArray2!=null) {
doubleArray2[row][col] = Double.parseDouble(val);
} else if(stringArray1!=null) {
stringArray1[row] = val;
} else if(stringArray2!=null) {
stringArray2[row][col] = val;
} else if(booleanArray1!=null) {
booleanArray1[row] = val.toLowerCase().startsWith("t"); //$NON-NLS-1$
} else if(booleanArray2!=null) {
booleanArray2[row][col] = val.toLowerCase().startsWith("t"); //$NON-NLS-1$
}
if(transposed)fireTableCellUpdated(col, row);
else fireTableCellUpdated(row, col);
}
} catch(Exception ex) {
//System.out.println("set value exception "+ex);
// do nothing on numeric format exceptions and out of bounds exceptions
}
}
/**
* Determines whether the given cell is editable.
*
* @param row the row index
* @param col the column index
* @return true if editable
*/
public boolean isCellEditable(int row, int col) {
if(showRowNumber&&(col==0)) {
return false; // row numbers are never editable
}
col = showRowNumber ? col-1 : col;
Boolean val = lockedColumns.get(col);
if(val==null) { // columns that are not in the dictionary are editable
return editable;
}
return !val&&editable;
}
}
/*
* 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
*/