package au.com.acpfg.misc.jemboss.settings; import java.awt.Dimension; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.logging.Logger; import javax.swing.Box; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.knime.core.data.DataCell; import org.knime.core.data.DataTableSpec; import org.knime.core.node.InvalidSettingsException; import au.com.acpfg.misc.jemboss.local.AbstractTableMapper; import au.com.acpfg.misc.jemboss.local.ProgramSettingsListener; /** * Represents an integer or floating-point number and provides an type-safe interface specific to the * number being edited * * @author andrew.cassin * */ public class NumberSetting extends StringSetting { private String m_lowerbound, m_upperbound; public NumberSetting(HashMap<String,String> attrs) { super(attrs); m_lowerbound = ""; m_upperbound = ""; if (attrs.containsKey("lowerbound") || attrs.containsKey("upperbound")) { setMinMax(attrs.get("lowerbound"), attrs.get("upperbound")); } } // TODO: provide a way to remove bound? protected void setMinimum(String min_val) { if (min_val != null && min_val.length() > 0) { m_lowerbound = min_val; } else { m_lowerbound = ""; } } // TODO: provide a way to remove bound? protected void setMaximum(String max_val) { if (max_val != null && max_val.length() > 0) { m_upperbound = max_val; } else { m_upperbound = ""; } } public final void setMinMax(String min_bound, String max_bound) { setMinimum(min_bound); setMaximum(max_bound); } @Override public String getColumnName() { return null; } @Override public JComponent make_widget(DataTableSpec dt) { JPanel p = new JPanel(); JSpinner sp = new JSpinner(); sp.setPreferredSize(new Dimension(100,25)); sp.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { JSpinner sp = ((JSpinner) arg0.getSource()); SpinnerNumberModel mdl = ((SpinnerNumberModel) sp.getModel()); setValue(mdl.getValue().toString()); } }); String t = getType(); boolean is_real = t.equals("float") || t.equals("double"); sp.setModel(make_number_model(is_real, getDefaultValue(), m_lowerbound, m_upperbound)); setValue(sp.getValue().toString()); p.add(sp); p.add(Box.createVerticalGlue()); return p; } @Override public void copy_attributes(HashMap<String,String> attrs) { super.copy_attributes(attrs); attrs.put("lowerbound", m_lowerbound); attrs.put("upperbound", m_upperbound); } @Override public void getArguments(ProgramSettingsListener l) { l.addArgument(this, new String[] { "-"+getName(), getValue() }); } /** * Returns a JSpinner number model instance which satisfies the specified constraints * @param default: default value (if any) * @param lower: lowerbound value (if any) * @param upper: upperbound value (if any) * This routine ignores, but logs, number constraints which cannot be resolved at configure-time. This routine is carefully * written so that the model has the correct type for the type of ProgramSetting (eg. float or integer) */ protected SpinnerNumberModel make_number_model(boolean is_real, String default_val, String lower_val, String upper_val) { //Logger.getAnonymousLogger().info(is_real+" <"+default_val+"> <"+lower_val+"> <"+upper_val+">"); Number val = new Integer(0); Number lower = new Integer(Integer.MIN_VALUE); Number upper = new Integer(Integer.MAX_VALUE); Number step_size = new Integer(1); boolean has_lower = false; boolean has_upper = false; if (is_real) { val = new Double(0.0); lower = new Double(-Double.MAX_VALUE); upper = new Double(Double.MAX_VALUE); step_size = new Double(1.0); } if (default_val.length() > 0) { try { if (is_real) val = new Double(default_val); else val = new Integer(default_val); } catch (NumberFormatException nfe) { Logger.getAnonymousLogger().warning("Cannot set default: "+default_val); // fallthru for bounds anyway... } } if (lower_val.length() > 0) { try { if (is_real) lower = new Double(lower_val); else lower = new Integer(lower_val); has_lower = true; } catch (NumberFormatException nfe) { Logger.getAnonymousLogger().warning("Cannot set lower bound: "+lower_val); } } if (upper_val.length() > 0) { try { if (is_real) upper = new Double(upper_val); else upper = new Integer(upper_val); has_upper = true; } catch (NumberFormatException nfe) { Logger.getAnonymousLogger().warning("Cannot set upper bound: "+upper_val); } } // TODO: if an ACD variable is specified, we cant resolve them at this time, so for safety... //Logger.getAnonymousLogger().info("val: <"+val+"> lower<"+lower+"> upper <"+upper+">"); if (has_lower && ((Comparable) val).compareTo(lower) < 0 ) { // val less than lower bound? val = lower; } if (has_upper && ((Comparable) val).compareTo(upper) > 0) { // val greater than upper bound? val = upper; } return new SpinnerNumberModel(val, (Comparable) lower, (Comparable) upper, step_size); } @Override public void marshal(String id, DataCell c, PrintWriter fw) throws IOException, InvalidSettingsException { // TODO Auto-generated method stub } public static boolean canEmboss(String acd_type) { if (acd_type.equals("integer") || acd_type.equals("float") || acd_type.equals("real")) { return true; } return false; } }