ConvertedValue.java [src/usda/weru/util] Revision: default Date:
/*
* ConvertedValue.java
*
* Created on December 28, 2005, 4:59 PM
*
* To change this template, choose Tools | Options and locate the template under
* the Source Creation and Management node. Right-click the template and choose
* Open. You can then make changes to the template in the Source Editor.
*/
package usda.weru.util;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
/**
* Stores a double value and maintains the measurement units the value may be
* displayed in. A hashtable creates ties between systems of measurement such as SI
* or US and their respective units as they apply to the stored value.
* @author Joseph Levin
*/
public class ConvertedValue{
/**
* The base units the value is stored in.
*/
private ConversionUnit c_baseUnits;
/**
* The currently active display units. This variable is assigned as unit systems are set.
*/
private ConversionUnit c_displayUnits;
/**
* Hashtable with system name / unit pairs. Used to tie a system, such as "SI" or "US" to a measurement unit.
*/
private Map <String, ConversionUnit> c_displayUnitsTable;
public static final String PROP_VALUE = "value";
public static final String PROP_DISPLAY_VALUE = "displayValue";
public static final String PROP_DISPLAY_UNIT = "displayUnits";
private PropertyChangeSupport c_changes;
/**
* Cached conversion factor. This will probally need to be moved to the
* ConversionCalculator class.
*/
private double c_factor;
/**
* Value being stored in base units.
*/
private double c_value;
/**
* Number format for toStringValue and toStringDisplayValue methods.
*/
private String c_valueOutputFormat = "#.##";
/**
* Prepares variables and objects.
*/
private void init(){
c_displayUnitsTable = new HashMap <String, ConversionUnit> ();
c_changes = new PropertyChangeSupport(this);
}
/**
* Default constructor. Uses a conversion factor of 1, and no units.
*/
public ConvertedValue(){
init();
c_factor = 1;
}
/**
* Recommended Constructor. Sets the base units and adds the base units to
* the display table with the passed system. The display units are set to the
* base units.
* @param system
* @param baseUnits
*/
public ConvertedValue(String system, String baseUnits){
init();
try{
c_baseUnits = ConversionCalculator.getUnitFromTag(baseUnits);
if (system != null && system.length() > 0){
addDisplayUnits(system, c_baseUnits);
setDisplaySystem(system);
}
else{
c_displayUnits = c_baseUnits;
}
updateConversionFactor();
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* Returns the base value stored.
* @return The double value stored. This is an unconverted value.
*/
public double getValue(){
return c_value;
}
/**
* Sets the base value.
* @param value The double value to be stored.
*/
public void setValue(double value){
double oldValue = c_value;
double oldDisplay = getDisplayValue();
c_value = value;
c_changes.firePropertyChange(PROP_VALUE, oldValue, value);
c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
}
/**
* Sets the measurement system to be used when the display value is requested.
* Use the addDisplayUnits method first to assign units to a system.
* @param system The measurement system to display the units in.
*/
public void setDisplaySystem(String system){
ConversionUnit unit = c_displayUnitsTable.get(system);
setDisplayUnits(unit);
// if (unit != null){
// double oldDisplay = getDisplayValue();
// c_displayUnits = unit;
// updateConversionFactor();
//
// c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
// }
// else{
// //System.err.println("There are no units for the " + system + " system of measurement.");
// }
}
/**
* Assign units to systems. Only one unit can be tied to a system. For
* example, assume the value represents area. The base units could be
* km^2 and then a unit could be added for SI and US display.
* addDisplayUnits("US", "ft^2");
* addDisplayUnits("SI", "m^2");
*
* Now the interface is only required to tell the ConvertedValue the
* desired display system.
*
* @param system The tag or name of the measurement system.
* @param units The measurement units to be associated with the system
*/
public void addDisplayUnits(String system, ConversionUnit units){
if (system == null || units == null) return;
c_displayUnitsTable.put(system, units);
}
/**
* Assigns units to systems. First looks up the unit from the conversion
* calculator.
* @param system The tag or name of the measurement system.
* @param units The measurement units to be associated with the system
*/
public void addDisplayUnits(String system, String units){
try{
ConversionUnit unit = ConversionCalculator.getUnitFromTag(units);
addDisplayUnits(system, unit);
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* If the current base and display units are not null then the conversion factor is calcuated and cached.
*/
private void updateConversionFactor(){
if (c_baseUnits == null || c_displayUnits == null){
c_factor = 1;
return;
}
try{
c_factor = ConversionCalculator.getConversionFactor(c_baseUnits, c_displayUnits);
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* Sets the display units to the given units. This method does not add the units to the display table.
* This method is used without unit systems.
* @param units The units the value should be displayed in.
*/
public void setDisplayUnits(String units){
try{
setDisplayUnits(ConversionCalculator.getUnitFromTag(units));
}
catch (Exception e){
e.printStackTrace();
}
}
public void setDisplayUnits(ConversionUnit units){
double oldDisplay = getDisplayValue();
ConversionUnit old = c_displayUnits;
c_displayUnits = units;
updateConversionFactor();
c_changes.firePropertyChange(PROP_DISPLAY_UNIT, old, c_displayUnits);
c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
}
/**
* Gets the units the value is being displayed in. These may be the same as the base units if no conversion is being applied.
* @return ConversionCalculator.Unit measurement unit
*/
public ConversionUnit getDisplayUnits(){
return c_displayUnits;
}
/**
* Sets the base units to the given units. This method does not affect the display table.
* This method is used without unit systems. This method does not affect the stored value.
* @param units The units the value should are stored in.
*/
public void setBaseUnits(String units){
try{
setBaseUnits(ConversionCalculator.getUnitFromTag(units));
}
catch (Exception e){
e.printStackTrace();
}
}
public void setBaseUnits(ConversionUnit units){
double oldValue = getValue();
double oldDisplay = getDisplayValue();
c_baseUnits = units;
updateConversionFactor();
c_changes.firePropertyChange(PROP_VALUE, oldValue, getValue());
c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
}
/**
* Gets the units the value is being stored in.
* @return ConversionCalculator.Unit measurement unit
*/
public ConversionUnit getBaseUnits(){
return c_baseUnits;
}
/**
* The value converted from the base units to the display units.
* @return double Converted value
*/
public double getDisplayValue(){
return c_value * c_factor;
}
/**
* This method converts the passed value from the display units to the base units and stores
* the value.
* @param value value in display units
*/
public void setDisplayValue(double value){
setValue(value / c_factor);
}
/**
* String representation of the display value. Applies the output format if possible. Default format is #.##.
* @return String The value in display units.
*/
public String toStringDisplayValue(){
if (c_valueOutputFormat.length() > 0){
try{
return new DecimalFormat(c_valueOutputFormat).format(getDisplayValue());
}
catch (NumberFormatException nfe){
return Double.toString(getDisplayValue());
}
}
else{
return Double.toString(getDisplayValue());
}
}
/**
* String representation of the base value. Applies the output format if possible. Default format is #.##.
* @return String The value in base units.
*/
public String toStringValue(){
if (c_valueOutputFormat.length() > 0){
try{
return new DecimalFormat(c_valueOutputFormat).format(getValue());
}
catch (NumberFormatException nfe){
return Double.toString(getValue());
}
}
else{
return Double.toString(getValue());
}
}
/**
* String representation of the base value. Does not apply the output format.
* @return String The value in base units.
*/
public String toString(){
return Double.toString(getValue());
}
/**
* Sets the output format used for the toStringValue and toStringDisplayValue methods. This
* format is intended to prevent too many digits after the decimal point when writing
* @param format the number format to apply to output.
*/
public void setOutputFormat(String format){
c_valueOutputFormat = format;
}
public void addPropertyChangeListener(PropertyChangeListener listener){
c_changes.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String property, PropertyChangeListener listener){
c_changes.addPropertyChangeListener(property, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener){
c_changes.removePropertyChangeListener(listener);
}
public void removePropertyChangeListener(String property, PropertyChangeListener listener){
c_changes.removePropertyChangeListener(property, listener);
}
}