/*
* 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.controls;
import java.awt.Color;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import org.opensourcephysics.numerics.DoubleArray;
import org.opensourcephysics.numerics.IntegerArray;
/**
*
* OSPControlTable automaitally converts strings, such "pi" or "sqrt(2)" to numbers when
* getDouble and getInt are invoked.
*
* @author W. Christian
* @version 1.1
*/
public class OSPControlTable extends XMLTable implements Control {
static Color ERROR_COLOR = Color.PINK;
private HashMap<String, Double> valueCache = new HashMap<String, Double>();
private boolean lockValues = false;
private DecimalFormat format;
/**
* Constructs OSPControlTable and creates an XMLControlElement.
*/
public OSPControlTable() {
this(new XMLControlElement());
}
/**
* Constructs OSPControlTable with the given control.
* @param control XMLControlElement
*/
public OSPControlTable(XMLControlElement control) {
super(control);
}
/**
* Locks the control's interface. Values sent to the control will not
* update the display until the control is unlocked.
*
* @param lock boolean
*/
public void setLockValues(boolean lock) {
tableModel.control.setLockValues(lock);
lockValues = lock;
if(!lockValues) {
refresh();
}
}
/**
* Adds a parameter to the input display.
*
* @param par the parameter name
* @param val the initial parameter value
*/
public void setValue(String par, Object val) {
if(getBackgroundColor(par)==ERROR_COLOR) {
setBackgroundColor(par, Color.WHITE);
}
tableModel.control.setValue(par, val);
if(!lockValues) {
refresh();
}
}
/**
* Sets the format pattern used for floating point numbers.
* @param pattern String
*/
public void setDecimalFormat(String pattern) {
if(pattern==null) {
format = null;
} else {
format = new DecimalFormat(pattern);
}
}
/**
* Adds an initial value of a parameter to the input display.
*
* @param par the parameter name
* @param val the initial parameter value
*/
public void setValue(String par, double val) {
if(format==null) {
setValue(par, Double.toString(val));
} else {
setValue(par, format.format(val));
}
if(!Double.isNaN(val)) {
valueCache.put(par, new Double(val)); // store last good value
}
}
/**
* Adds an initial value of a parameter to the input display.
*
* @param par the parameter name
* @param val the initial parameter value
*/
public void setValue(String par, int val) {
setValue(par, Integer.toString(val));
valueCache.put(par, new Double(val)); // store last good value
}
public void setValue(String par, boolean val) {
if(getBackgroundColor(par)==ERROR_COLOR) {
setBackgroundColor(par, Color.WHITE);
}
tableModel.control.setValue(par, val);
}
/**
* Reads a parameter value from the input display.
*
* @param par
* @return int the value of of the parameter
*/
public int getInt(String par) {
String str = tableModel.control.getString(par);
if(str==null) {
str = getObject(par).toString();
}
// special handling for OSPCombo
if(tableModel.control.getPropertyType(par).equals("object")) { //$NON-NLS-1$
XMLControl c = tableModel.control.getChildControl(par);
if(c.getObjectClass()==OSPCombo.class) {
OSPCombo combo = (OSPCombo) c.loadObject(null);
return combo.getSelectedIndex();
}
}
if(str==null) {
setBackgroundColor(par, ERROR_COLOR);
refresh();
if(valueCache.containsKey(par)) {
return(int) valueCache.get(par).doubleValue();
}
return 0;
}
Color color = cellColors.get(par);
boolean editable = isEditable(par);
try {
int val = Integer.parseInt(par);
if(editable&&(color!=Color.WHITE)) { // background is not correct so change it
setBackgroundColor(par, Color.WHITE);
refresh();
} else if(!editable&&(color!=Control.NOT_EDITABLE_BACKGROUND)) { // background is not correct so change it
setBackgroundColor(par, Control.NOT_EDITABLE_BACKGROUND);
refresh();
}
valueCache.put(par, new Double(val));
return val;
} catch(NumberFormatException ex) {}
try {
int val = (int) Double.parseDouble(par);
if(editable&&(color!=Color.WHITE)) { // background is not correct so change it
setBackgroundColor(par, Color.WHITE);
refresh();
} else if(!editable&&(color!=Control.NOT_EDITABLE_BACKGROUND)) { // background is not correct so change it
setBackgroundColor(par, Control.NOT_EDITABLE_BACKGROUND);
refresh();
}
valueCache.put(par, new Double(val));
return val;
} catch(NumberFormatException ex) {}
double dval = org.opensourcephysics.numerics.Util.evalMath(str);
if(Double.isNaN(dval)&&(color!=ERROR_COLOR)) {
setBackgroundColor(par, ERROR_COLOR);
refresh();
if(valueCache.containsKey(par)) {
return(int) valueCache.get(par).doubleValue();
}
return 0;
}
if(editable&&(color!=Color.WHITE)) { // background is not correct so change it
setBackgroundColor(par, Color.WHITE);
refresh();
} else if(!editable&&(color!=Control.NOT_EDITABLE_BACKGROUND)) { // background is not correct so change it
setBackgroundColor(par, Control.NOT_EDITABLE_BACKGROUND);
refresh();
}
valueCache.put(par, new Double(dval));
return(int) dval;
}
/**
* Test if the last "get" method produced an input error.
*
* @param par String
* @return boolean
*/
public boolean inputError(String par) {
return getBackgroundColor(par)==ERROR_COLOR;
}
/**
* Reads a double value from the table.
*
* @param par String the parameter key
* @return double the value of of the parameter
*/
public double getDouble(String par) {
String str = tableModel.control.getString(par);
if(str==null) {
str = getObject(par).toString();
}
if(str==null) {
setBackgroundColor(par, ERROR_COLOR);
refresh();
if(valueCache.containsKey(par)) {
return valueCache.get(par).doubleValue();
}
return 0;
}
Color color = cellColors.get(par);
boolean editable = isEditable(par);
try {
double val = Double.parseDouble(str);
if(editable&&(color!=Color.WHITE)) { // background is not correct so change it
setBackgroundColor(par, Color.WHITE);
refresh();
} else if(!editable&&(color!=Control.NOT_EDITABLE_BACKGROUND)) { // background is not correct so change it
setBackgroundColor(par, Control.NOT_EDITABLE_BACKGROUND);
refresh();
}
valueCache.put(par, new Double(val));
return val;
} catch(NumberFormatException ex) {}
double val = org.opensourcephysics.numerics.Util.evalMath(str);
if(Double.isNaN(val)&&(color!=ERROR_COLOR)) { // string is not a valid number
setBackgroundColor(par, ERROR_COLOR);
refresh();
} else if(editable&&(color!=Color.WHITE)) { // background is not correct so change it
setBackgroundColor(par, Color.WHITE);
refresh();
} else if(!editable&&(color!=Control.NOT_EDITABLE_BACKGROUND)) { // background is not correct so change it
setBackgroundColor(par, Control.NOT_EDITABLE_BACKGROUND);
refresh();
}
if(Double.isNaN(val)&&valueCache.containsKey(par)) {
val = valueCache.get(par).doubleValue();
} else {
valueCache.put(par, new Double(val));
}
return val;
}
/**
* Gets the object with the specified property name.
* Throws an UnsupportedOperationException if the named object has not been stored.
*
* @param par
* @return the object
*/
public Object getObject(String par) throws UnsupportedOperationException {
return tableModel.control.getObject(par);
}
public String getString(String par) {
return tableModel.control.getString(par);
}
public boolean getBoolean(String par) {
return tableModel.control.getBoolean(par);
}
public Collection<String> getPropertyNames() {
return tableModel.control.getPropertyNames();
}
/**
* Removes a parameter from the table.
*
* @param par the parameter name
*/
public void removeParameter(String par) {
tableModel.control.setValue(par, null);
setBackgroundColor(par, Color.WHITE);
}
public void println(String s) {
tableModel.control.println(s);
}
public void println() {
tableModel.control.println();
}
public void print(String s) {
tableModel.control.print(s);
}
public void clearMessages() {
tableModel.control.clearMessages();
}
public void clearValues() {
tableModel.control.clearValues();
}
public void calculationDone(String message) {
if(message!=null) {
tableModel.control.calculationDone(message);
}
}
/**
* Returns an XML.ObjectLoader to save and load data for this object.
*
* @return the object loader
*/
public static XML.ObjectLoader getLoader() {
return new OSPControlTableLoader();
}
/**
* A class to save and load data for OSPControls.
*/
static class OSPControlTableLoader implements XML.ObjectLoader {
/**
* Saves object data to an XMLControl.
*
* @param prefsXMLControl the control to save to
* @param obj the object to save
*/
public void saveObject(XMLControl xmlControl, Object obj) {
OSPControlTable controlTable = (OSPControlTable) obj;
Iterator<String> it = controlTable.getPropertyNames().iterator();
while(it.hasNext()) {
String name = it.next();
Object val = controlTable.getObject(name);
if(val.getClass()==DoubleArray.class) {
xmlControl.setValue(name, ((DoubleArray) val).getArray());
} else if(val.getClass()==IntegerArray.class) {
xmlControl.setValue(name, ((IntegerArray) val).getArray());
} else if(val.getClass()==Boolean.class) {
xmlControl.setValue(name, ((Boolean) val).booleanValue());
} else if(val.getClass()==Double.class) {
xmlControl.setValue(name, ((Double) val).doubleValue());
} else if(val.getClass()==Integer.class) {
xmlControl.setValue(name, ((Integer) val).intValue());
} else if(val.getClass().isArray()) {
xmlControl.setValue(name, val);
} else {
xmlControl.setValue(name, val);
}
}
}
/**
* Creates an OSPControlTable object.
*
* @param control the control
* @return the newly created object
*/
public Object createObject(XMLControl control) {
return new OSPControlTable();
}
/**
* Loads an object with data from an XMLControl.
*
* @param control the control
* @param obj the object
* @return the loaded object
*/
public Object loadObject(XMLControl control, Object obj) {
OSPControlTable controlTable = (OSPControlTable) obj;
// iterate over properties and add them to table model
Iterator<String> it = control.getPropertyNames().iterator();
controlTable.setLockValues(true);
while(it.hasNext()) {
String name = it.next();
if(control.getPropertyType(name).equals("string")) { //$NON-NLS-1$
controlTable.setValue(name, control.getString(name));
} else if(control.getPropertyType(name).equals("int")) { //$NON-NLS-1$
controlTable.setValue(name, control.getInt(name));
} else if(control.getPropertyType(name).equals("double")) { //$NON-NLS-1$
controlTable.setValue(name, control.getDouble(name));
} else if(control.getPropertyType(name).equals("boolean")) { //$NON-NLS-1$
controlTable.setValue(name, control.getBoolean(name));
} else {
controlTable.setValue(name, control.getObject(name));
}
}
controlTable.setLockValues(false);
return obj;
}
}
}
/*
* 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
*/