001    package jigcell.compare.compare2;
002    
003    import java.awt.event.ActionEvent;
004    import java.awt.event.ActionListener;
005    import java.awt.event.ItemEvent;
006    import java.awt.event.ItemListener;
007    import java.beans.PropertyChangeEvent;
008    import java.beans.PropertyChangeListener;
009    import java.text.DecimalFormat;
010    import java.util.ArrayList;
011    import java.util.Hashtable;
012    import java.util.List;
013    import java.util.Map;
014    import javax.swing.DefaultBoundedRangeModel;
015    import javax.swing.JDialog;
016    import javax.swing.JLabel;
017    import javax.swing.JSlider;
018    import javax.swing.event.ChangeEvent;
019    import javax.swing.event.ChangeListener;
020    import javax.swing.text.Document;
021    import javax.swing.text.PlainDocument;
022    import jigcell.compare.data.IDataGeneratorCollection;
023    import jigcell.compare.impl.Compare;
024    import jigcell.compare.ui.ListComboBoxModel;
025    import jigcell.compare.ui.InterfaceBuilder;
026    
027    /**
028     * Editor for comparison thresholds.
029     *
030     * <p>
031     * This code is licensed under the DARPA BioCOMP Open Source License.  See LICENSE for more details.
032     * </p>
033     *
034     * @author Nicholas Allen
035     */
036    
037    public class ThresholdEditor extends JDialog implements ActionListener, ChangeListener, ItemListener, PropertyChangeListener {
038    
039       /**
040        * Base point for the threshold slider
041        */
042    
043       protected final static int SLIDER_BASE = 100;
044    
045       /**
046        * Maximum point for the threshold slider
047        */
048    
049       protected final static int SLIDER_MAX = SLIDER_BASE << 1;
050    
051       /**
052        * Label for the experiment name
053        */
054    
055       protected final static String LABEL_EXPERIMENT = "Experiment:";
056    
057       /**
058        * Name for experiment threshold components
059        */
060    
061       protected final static String NAME_THRESHOLD = "threshold";
062    
063       /**
064        * Comparator of parent view
065        */
066    
067       protected Compare compare;
068    
069       /**
070        * View model
071        */
072    
073       protected Compare2Model model;
074    
075       /**
076        * Document storing the threshold value
077        */
078    
079       protected Document thresholdDocument;
080    
081       /**
082        * Threshold value before any adjustments were made
083        */
084    
085       protected double originalThreshold;
086    
087       /**
088        * Experiment currently being edited
089        */
090    
091       protected IDataGeneratorCollection.Key currentExperiment;
092    
093       /**
094        * Manages the interface for this editor
095        */
096    
097       protected InterfaceBuilder manager;
098    
099       /**
100        * Slider for adjusting the threshold value
101        */
102    
103       protected JSlider thresholdSlider;
104    
105       /**
106        * Model for the list of experiments
107        */
108    
109       protected ListComboBoxModel experimentBoxModel;
110    
111       /**
112        * Map[IDataGeneratorCollection.Key,String] of the keys of experiments to the threshold
113        */
114    
115       protected Map experimentThresholds;
116    
117       /**
118        * Formatter for displaying threshold values
119        */
120    
121       protected DecimalFormat thresholdFormat;
122    
123       /**
124        * Creates a new display for editing thresholds.
125        *
126        * @param compare Comparator to use
127        * @param model View model
128        * @param experimentThresholds Map from experiment names to thresholds
129        */
130    
131       public ThresholdEditor (Compare compare, Compare2Model model, Map experimentThresholds) {
132          super (compare.getDisplayFrame (), Compare.getString ("ThresholdEditor.title"), false);
133          this.compare = compare;
134          this.model = model;
135          this.experimentThresholds = experimentThresholds;
136          createUI ();
137          compare.addPropertyChangeListener (this);
138          indexExperiments ();
139          setVisible (true);
140       }
141    
142       public void createUI () {
143          thresholdFormat = new DecimalFormat ("##0.#####E0");
144          thresholdFormat.setDecimalSeparatorAlwaysShown (true);
145          setDefaultCloseOperation (HIDE_ON_CLOSE);
146          setLocationRelativeTo (null);
147          manager = new InterfaceBuilder (this);
148          manager.addLabel (LABEL_EXPERIMENT);
149          experimentBoxModel = new ListComboBoxModel ();
150          manager.addComboBox (LABEL_EXPERIMENT, experimentBoxModel);
151          manager.endRow (true);
152          thresholdSlider = manager.addSlider (NAME_THRESHOLD, new DefaultBoundedRangeModel (SLIDER_BASE, 0, 0, SLIDER_MAX));
153          thresholdSlider.setMajorTickSpacing (SLIDER_MAX / 10);
154          thresholdSlider.setMinorTickSpacing (SLIDER_MAX / 20);
155          thresholdSlider.setPaintLabels (true);
156          thresholdSlider.setPaintTicks (true);
157          manager.endBlock ();
158          thresholdDocument = new PlainDocument ();
159          manager.addTextField (NAME_THRESHOLD, thresholdDocument, 15);
160          getContentPane ().add (manager.endInterface ());
161          pack ();
162       }
163    
164       public void actionPerformed (ActionEvent e) {
165          if (NAME_THRESHOLD.equals (manager.getComponentName (e.getSource ())))
166             setThreshold (InterfaceBuilder.readDocument (thresholdDocument), true);
167       }
168    
169       public void itemStateChanged (ItemEvent e) {
170          if (LABEL_EXPERIMENT.equals (manager.getComponentName (e.getSource ())))
171             setExperiment ((IDataGeneratorCollection.Key) e.getItem ());
172       }
173    
174       public void propertyChange (PropertyChangeEvent e) {
175          String name = e.getPropertyName ();
176          if (Compare2Model.PROPERTY_EXPERIMENTTHRESHOLDS_EDIT.equals (name)) {
177             try {
178                String documentThreshold = InterfaceBuilder.readDocument (thresholdDocument);
179                String actualThreshold = (String) experimentThresholds.get (currentExperiment);
180                if (documentThreshold == actualThreshold || documentThreshold != null && documentThreshold.equals (actualThreshold))
181                   return;
182             } catch (Exception _e) {}
183             updateDisplay (true);
184             return;
185          }
186          if (Compare2Model.RESOURCE_EXPERIMENTTHRESHOLDS.equals (name)) {
187             indexExperiments ();
188          }
189       }
190    
191       /**
192        * Sets the experiment which this editor is working with.
193        *
194        * @param experiment Experiment name
195        */
196    
197       public void setExperiment (IDataGeneratorCollection.Key experiment) {
198          if (experiment == null)
199             throw new IllegalArgumentException ();
200          if (currentExperiment == experiment)
201             return;
202          currentExperiment = experiment;
203          experimentBoxModel.setSelectedItem (experiment);
204          updateDisplay (true);
205       }
206    
207       /**
208        * Sets the threshold for the experiment this editor is working with.
209        *
210        * @param value Threshold value
211        * @param reset Reset the base threshold value
212        */
213    
214       public void setThreshold (String value, boolean reset) {
215          try {
216             setThreshold (Double.parseDouble (value), reset);
217          } catch (Exception e) {
218             compare.shellHandleException (Compare.MESSAGE_ERROR, Compare.getString ("ThresholdEditor.editError"), e);
219          }
220       }
221    
222       /**
223        * Sets the threshold for the experiment this editor is working with.
224        *
225        * @param threshold Threshold
226        * @param reset Reset the base threshold value
227        */
228    
229       public void setThreshold (double threshold, boolean reset) {
230          if (currentExperiment == null)
231             throw new IllegalStateException ();
232          if (threshold < 0.0)
233             throw new IllegalArgumentException (Compare.getString ("ThresholdEditor.negativeThresholdError"));
234          experimentThresholds.put (currentExperiment, thresholdFormat.format (threshold));
235          updateDisplay (reset);
236          compare.firePropertyChange (Compare2Model.PROPERTY_EXPERIMENTTHRESHOLDS_EDIT);
237          model.fireTableDataChanged ();
238       }
239    
240       public void stateChanged (ChangeEvent e) {
241          if (NAME_THRESHOLD.equals (manager.getComponentName (e.getSource ())))
242             setThreshold (originalThreshold * (thresholdSlider.getValue () / (double) SLIDER_BASE), false);
243       }
244    
245       /**
246        * Creates a list of the known experiments.
247        */
248    
249       protected void indexExperiments () {
250          List experiments = new ArrayList (experimentThresholds.keySet ());
251          experimentBoxModel.replaceAll (experiments);
252          if (experiments.isEmpty ())
253             setVisible (false);
254          else if (experimentBoxModel.getSelectedItem () == null)
255             setExperiment ((IDataGeneratorCollection.Key) experiments.get (0));
256       }
257    
258       /**
259        * Resets the editing controls.
260        */
261    
262       protected void resetControls () {
263          thresholdSlider.setValue (SLIDER_BASE);
264          boolean enabled = originalThreshold != 0.0;
265          thresholdSlider.setEnabled (enabled);
266          thresholdSlider.setPaintLabels (enabled);
267          thresholdSlider.setPaintTicks (enabled);
268          if (!enabled)
269             return;
270          String value = thresholdFormat.format (originalThreshold);
271          Hashtable labels = new Hashtable ();
272          labels.put (new Integer (0), new JLabel ("0"));
273          labels.put (new Integer (SLIDER_BASE), new JLabel (value));
274          labels.put (new Integer (SLIDER_MAX), new JLabel (thresholdFormat.format (originalThreshold * 2)));
275          thresholdSlider.setLabelTable (labels);
276       }
277    
278       /**
279        * Updates the display with the latest threshold value.
280        *
281        * @param reset Reset the base threshold value
282        */
283    
284       protected void updateDisplay (boolean reset) {
285          double threshold;
286          try {
287             threshold = Double.parseDouble ((String) experimentThresholds.get (currentExperiment));
288          } catch (Exception e) {
289             threshold = 0.0;
290          }
291          InterfaceBuilder.replaceDocument (thresholdDocument, thresholdFormat.format (threshold));
292          if (!reset)
293             return;
294          originalThreshold = threshold;
295          resetControls ();
296       }
297    }