001/*
002 * $Id: HydraCombo.java,v 1.23 2011/03/24 16:06:32 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030
031package edu.wisc.ssec.mcidasv.control;
032
033import java.awt.Color;
034import java.awt.Container;
035import java.awt.FlowLayout;
036import java.awt.event.ActionEvent;
037import java.awt.event.ActionListener;
038import java.rmi.RemoteException;
039import java.util.ArrayList;
040import java.util.HashMap;
041import java.util.Hashtable;
042import java.util.List;
043import java.util.Map;
044
045import javax.swing.JButton;
046import javax.swing.JComboBox;
047import javax.swing.JComponent;
048import javax.swing.JLabel;
049import javax.swing.JPanel;
050import javax.swing.JTabbedPane;
051import javax.swing.JTextField;
052import javax.swing.border.LineBorder;
053
054import org.python.core.PyObject;
055
056import visad.ConstantMap;
057import visad.Data;
058import visad.VisADException;
059import visad.georef.MapProjection;
060
061import ucar.unidata.data.DataChoice;
062import ucar.unidata.data.DataSource;
063import ucar.unidata.data.DirectDataChoice;
064import ucar.unidata.idv.MapViewManager;
065import ucar.unidata.util.GuiUtils;
066import ucar.unidata.util.LogUtil;
067import ucar.unidata.view.geoloc.MapProjectionDisplay;
068import ucar.visad.display.DisplayMaster;
069
070import edu.wisc.ssec.mcidasv.Constants;
071import edu.wisc.ssec.mcidasv.McIDASV;
072import edu.wisc.ssec.mcidasv.control.LinearCombo.Combination;
073import edu.wisc.ssec.mcidasv.control.LinearCombo.Selector;
074import edu.wisc.ssec.mcidasv.data.hydra.MultiDimensionSubset;
075import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralData;
076import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralDataSource;
077import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
078import edu.wisc.ssec.mcidasv.jython.Console;
079import edu.wisc.ssec.mcidasv.jython.ConsoleCallback;
080
081public class HydraCombo extends HydraControl {
082
083    private String sourceFile = "";
084
085    private MultiSpectralDisplay display;
086
087    private DisplayMaster displayMaster;
088
089    private DataChoice dataChoice = null;
090
091    private CombinationPanel comboPanel;
092
093    private final Hashtable<String, Object> persistable = new Hashtable<String, Object>();
094    
095    private MultiSpectralDataSource source;
096 
097    float init_wavenumber;
098
099    private Map<String, Selector> selectorMap = new HashMap<String, Selector>();
100
101    private static final String defaultButtonLabel = "Compute New Field";
102    private static final String thinkingButtonLabel = "thinking...";
103    private JButton computeButton = new JButton(defaultButtonLabel);
104
105    public HydraCombo() {
106        super();
107        setHelpUrl("idv.controls.hydra.channelcombinationcontrol");
108    }
109
110    @Override public boolean init(final DataChoice choice)
111        throws VisADException, RemoteException {
112        ((McIDASV)getIdv()).getMcvDataManager().setHydraControl(choice, this);
113        dataChoice = choice;
114        List<DataSource> sources = new ArrayList<DataSource>();
115        choice.getDataSources(sources);
116        source = ((MultiSpectralDataSource)sources.get(0));
117        sourceFile = ((MultiSpectralDataSource)sources.get(0)).getDatasetName();
118
119        Float fieldSelectorChannel = (Float)getDataSelection().getProperty(Constants.PROP_CHAN);
120        if (fieldSelectorChannel == null)
121            fieldSelectorChannel = 0f;
122        init_wavenumber = fieldSelectorChannel;
123
124        display = new MultiSpectralDisplay((DirectDataChoice)choice);
125        display.setWaveNumber(fieldSelectorChannel);
126        display.setDisplayControl(this);
127
128        ((McIDASV)getIdv()).getMcvDataManager().setHydraDisplay(choice, display);
129
130        comboPanel = new CombinationPanel(this);
131        if (!persistable.isEmpty()) {
132            comboPanel.unpersistData(persistable);
133            persistable.clear();
134        }
135        return true;
136    }
137
138    @Override public void initDone() {
139        MapViewManager viewManager = (MapViewManager) getViewManager();
140        MapProjectionDisplay dispMaster =
141            (MapProjectionDisplay) viewManager.getMaster();
142        try {
143          dispMaster.setMapProjection(getDataProjection());
144        } catch (Exception e) {
145          logException("problem setting MapProjection", e);
146        }
147
148        getIdv().getIdvUIManager().showDashboard();
149    }
150
151    public Hashtable<String, Object> getPersistable() {
152        return comboPanel.persistData();
153    }
154    
155    public void setPersistable(final Hashtable<String, Object> table) {
156        persistable.clear();
157        persistable.putAll(table);
158    }
159    
160    @Override public MapProjection getDataProjection() {
161        MapProjection mp = null;
162        HashMap subset = null;
163        Hashtable table = dataChoice.getProperties();
164        MultiDimensionSubset dataSel =
165           (MultiDimensionSubset) table.get(MultiDimensionSubset.key);
166        if (dataSel != null) {
167          subset = dataSel.getSubset();
168        }
169        mp = source.getDataProjection(subset);
170        return mp;
171    }
172
173    @Override public Container doMakeContents() {
174        JTabbedPane pane = new JTabbedPane();
175        pane.add("Channel Combination Tool", GuiUtils.inset(getComboTab(), 5));
176        GuiUtils.handleHeavyWeightComponentsInTabs(pane);
177        return pane;
178    }
179
180    public void updateComboPanel(final String id, final float value) {
181        if (comboPanel == null)
182            return;
183        comboPanel.updateSelector(id, value);
184    }
185
186    protected void enableSelectorForWrapper(final SelectorWrapper wrapper) {
187        if (comboPanel == null)
188            return;
189        comboPanel.enableSelector(wrapper, false);
190    }
191
192    protected void disableSelectorForWrapper(final SelectorWrapper wrapper) {
193        if (comboPanel == null)
194            return;
195        comboPanel.disableSelector(wrapper, false);
196    }
197    
198    protected MultiSpectralDisplay getMultiSpectralDisplay() {
199        return display;
200    }
201
202    protected JButton getComputeButton() {
203        return computeButton;
204    }
205
206    private JComponent getComboTab() {
207        computeButton.addActionListener(new ActionListener() {
208            public void actionPerformed(final ActionEvent e) {
209                comboPanel.queueCombination();
210//                computeButton.setText(thinkingButtonLabel);
211                computeButton.setEnabled(false);
212                showWaitCursor();
213            }
214        });
215        JPanel tmp = GuiUtils.topCenterBottom(display.getDisplayComponent(), comboPanel.getPanel(), computeButton);
216        return tmp;
217    }
218
219    public void addCombination(final String name, final Data combination) {
220        if (combination != null)
221            source.addChoice(name, combination);
222    }
223    
224    public void addCombination(final Combination combination) {
225        if (combination != null)
226            source.addChoice(combination.getName(), combination.getData());
227    }
228
229    protected void addSelector(final Selector selector) throws Exception {
230        ConstantMap[] mapping = selector.getColor();
231        float r = new Double(mapping[0].getConstant()).floatValue();
232        float g = new Double(mapping[1].getConstant()).floatValue();
233        float b = new Double(mapping[2].getConstant()).floatValue();
234        Color javaColor = new Color(r, g, b);
235        display.createSelector(selector.getId(), javaColor);
236        display.setSelectorValue(selector.getId(), selector.getWaveNumber());
237        selectorMap.put(selector.getId(), selector);
238    }
239
240    public void moveSelector(final String id, final float wavenum) {
241        if (!selectorMap.containsKey(id))
242            return;
243        display.updateControlSelector(id, wavenum);
244    }
245
246    public void updateSelector(final String id, final float wavenum) {
247        if (!selectorMap.containsKey(id))
248            return;
249
250        selectorMap.get(id).setWaveNumber(wavenum);
251    }
252
253    
254
255    public enum DataType { HYPERSPECTRAL, MULTISPECTRAL };
256
257    public enum WrapperState { ENABLED, DISABLED };
258
259    public static class CombinationPanel implements ConsoleCallback {
260        private final SelectorWrapper a;
261        private final SelectorWrapper b;
262        private final SelectorWrapper c;
263        private final SelectorWrapper d;
264
265        private final OperationXY ab;
266        private final OperationXY cd;
267
268        private final CombineOperations abcd;
269
270        private final MultiSpectralDisplay display;
271
272        private final HydraCombo control;
273
274        private final Console console;
275
276        private final Map<String, Selector> selectorMap = new HashMap<String, Selector>();
277        private final Map<String, SelectorWrapper> wrapperMap = new HashMap<String, SelectorWrapper>();
278
279        private final DataType dataType;
280
281        public CombinationPanel(final HydraCombo control) {
282            this.control = control;
283            display = control.getMultiSpectralDisplay();
284            if (display == null)
285                throw new NullPointerException("Display hasn't been initialized");
286
287            MultiSpectralData data = display.getMultiSpectralData();
288            if (data.hasBandNames())
289                dataType = DataType.MULTISPECTRAL;
290            else
291                dataType = DataType.HYPERSPECTRAL;
292
293            this.console = new Console();
294            console.setCallbackHandler(this);
295
296            a = makeWrapper("a", Color.RED);
297            b = makeWrapper("b", Color.GREEN);
298            c = makeWrapper("c", Color.BLUE);
299            d = makeWrapper("d", Color.MAGENTA);
300
301            enableSelector(a, true);
302
303            ab = new OperationXY(this, a, b);
304            cd = new OperationXY(this, c, d);
305
306            abcd = new CombineOperations(this, ab, cd);
307        }
308
309//        public Console getConsole() {
310//            return console;
311//        }
312
313        public void ranBlock(final String line) {
314            PyObject jythonObj = console.getJythonObject("combo");
315//            if (jythonObj instanceof PyJavaInstance) {
316                Object combination = jythonObj.__tojava__(Object.class);
317                if (combination instanceof Combination) {
318                    control.addCombination((Combination)combination);
319                    control.getComputeButton().setEnabled(true);
320                    control.showNormalCursor();
321                }
322//            }
323        }
324
325        public void updateSelector(final String id, final float channel) {
326            if (!selectorMap.containsKey(id))
327                return;
328
329            Selector selector = selectorMap.get(id);
330            selector.setWaveNumber(channel);
331            wrapperMap.get(id).update();
332        }
333
334        protected void addSelector(final Selector selector, final boolean enabled) throws Exception {
335            String id = selector.getId();
336            if (enabled) {
337                display.createSelector(id, selector.getColor());
338                display.setSelectorValue(id, selector.getWaveNumber());
339            }
340            selectorMap.put(id, selector);
341        }
342
343        protected void disableSelector(final SelectorWrapper wrapper, final boolean disableWrapper) {
344            if (disableWrapper)
345                wrapper.disable();
346
347            try {
348                display.removeSelector(wrapper.getSelector().getId());
349            } catch (Exception e) {
350                LogUtil.logException("HydraCombo.disableSelector", e);
351            }
352        }
353
354        protected void enableSelector(final SelectorWrapper wrapper, final boolean enableWrapper) {
355            if (enableWrapper)
356                wrapper.enable();
357
358            try {
359                Selector selector = wrapper.getSelector();
360                String id = selector.getId();
361                display.createSelector(id, selector.getColor());
362                display.setSelectorValue(id, selector.getWaveNumber());
363            } catch (Exception e) {
364                LogUtil.logException("HydraCombo.disableSelector", e);
365            }
366        }
367
368        private SelectorWrapper makeWrapper(final String var, final Color color) {
369            try {
370                ConstantMap[] mappedColor = MultiSpectralDisplay.makeColorMap(color);
371                
372                SelectorWrapper tmp;
373                if (dataType == DataType.HYPERSPECTRAL)
374                    tmp = new HyperspectralSelectorWrapper(var, mappedColor, control, console);
375                else
376                    tmp = new MultispectralSelectorWrapper(var, mappedColor, control, console);
377                addSelector(tmp.getSelector(), false);
378                wrapperMap.put(tmp.getSelector().getId(), tmp);
379//                console.injectObject(var, new PyJavaInstance(tmp.getSelector()));
380                console.injectObject(var, tmp.getSelector());
381                return tmp;
382            } catch (Exception e) { 
383                LogUtil.logException("HydraCombo.makeWrapper", e);
384            }
385            return null;
386        }
387
388        public JPanel getPanel() {
389            JPanel panel = new JPanel(new FlowLayout());
390            panel.add(new JLabel("("));
391            panel.add(a.getPanel());
392            panel.add(ab.getBox());
393            panel.add(b.getPanel());
394            panel.add(new JLabel(")"));
395            panel.add(abcd.getBox());
396            panel.add(new JLabel("("));
397            panel.add(c.getPanel());
398            panel.add(cd.getBox());
399            panel.add(d.getPanel());
400            panel.add(new JLabel(")"));
401            return panel;
402        }
403
404        public void queueCombination() {
405            String jy = "combo="+abcd.getJython();
406            System.err.println("jython=" + jy);
407            console.queueLine(jy);
408        }
409
410        public Hashtable<String, Object> persistData() {
411            Hashtable<String, Object> table = new Hashtable<String, Object>();
412            
413            table.put("a", a.persistSelectorWrapper());
414            table.put("b", b.persistSelectorWrapper());
415            table.put("c", c.persistSelectorWrapper());
416            table.put("d", d.persistSelectorWrapper());
417            table.put("ab", ab.getOperation());
418            table.put("cd", cd.getOperation());
419            table.put("abcd", abcd.getOperation());
420            return table;
421        }
422
423        public void unpersistData(final Hashtable<String, Object> table) {
424            Hashtable<String, String> tableA = (Hashtable<String, String>)table.get("a");
425            Hashtable<String, String> tableB = (Hashtable<String, String>)table.get("b");
426            Hashtable<String, String> tableC = (Hashtable<String, String>)table.get("c");
427            Hashtable<String, String> tableD = (Hashtable<String, String>)table.get("d");
428
429            a.unpersistSelectorWrapper(tableA);
430            b.unpersistSelectorWrapper(tableB);
431            c.unpersistSelectorWrapper(tableC);
432            d.unpersistSelectorWrapper(tableD);
433
434            String opAb = (String)table.get("ab");
435            String opCd = (String)table.get("cd");
436            String opAbcd = (String)table.get("abcd");
437
438            ab.setOperation(opAb);
439            cd.setOperation(opCd);
440            abcd.setOperation(opAbcd);
441        }
442    }
443
444    private static class OperationXY {
445        private static final String[] OPERATIONS = { "+", "-", "/", "*", " " };
446        private static final String INVALID_OP = " ";
447        private final JComboBox combo = new JComboBox(OPERATIONS);
448
449        private CombinationPanel comboPanel;
450        private SelectorWrapper x;
451        private SelectorWrapper y;
452
453        public OperationXY(final CombinationPanel comboPanel, final SelectorWrapper x, final SelectorWrapper y) {
454            this.x = x;
455            this.y = y;
456            this.comboPanel = comboPanel;
457            combo.setSelectedItem(" ");
458            combo.addActionListener(new ActionListener() {
459                public void actionPerformed(final ActionEvent e) {
460                    if (getOperation().equals(" ")) {
461                        comboPanel.disableSelector(y, true);
462                    } else {
463                        comboPanel.enableSelector(y, true);
464                    }
465                }
466            });
467        }
468
469        public void disable() {
470            comboPanel.disableSelector(x, true);
471            combo.setSelectedItem(INVALID_OP);
472            comboPanel.disableSelector(y, true);
473        }
474
475        public void enable() {
476            comboPanel.enableSelector(x, true);
477        }
478
479        public String getOperation() {
480            return (String)combo.getSelectedItem();
481        }
482
483        public void setOperation(final String operation) {
484            combo.setSelectedItem(operation);
485        }
486
487        public JComboBox getBox() {
488            return combo;
489        }
490
491        public String getJython() {
492            String operation = getOperation();
493            if (operation.equals(INVALID_OP))
494                operation = "";
495
496            String jython = x.getJython() + operation + y.getJython();
497            if (x.isValid() && y.isValid())
498                return "(" + jython + ")";
499            return jython;
500        }
501    }
502
503    private static class CombineOperations {
504        private static final String[] OPERATIONS = { "+", "-", "/", "*", " "};
505        private static final String INVALID_OP = " ";
506        private final JComboBox combo = new JComboBox(OPERATIONS);
507
508        private CombinationPanel comboPanel;
509        private OperationXY x;
510        private OperationXY y;
511
512        public CombineOperations(final CombinationPanel comboPanel, final OperationXY x, final OperationXY y) {
513            this.comboPanel = comboPanel;
514            this.x = x;
515            this.y = y;
516            combo.setSelectedItem(INVALID_OP);
517            combo.addActionListener(new ActionListener() {
518                public void actionPerformed(final ActionEvent e) {
519                    if (getOperation().equals(" ")) {
520                        y.disable();
521                    } else {
522                        y.enable();
523                    }
524                }
525            });
526        }
527
528        public String getOperation() {
529            return (String)combo.getSelectedItem();
530        }
531
532        public void setOperation(final String operation) {
533            combo.setSelectedItem(operation);
534        }
535
536        public JComboBox getBox() {
537            return combo;
538        }
539
540        public String getJython() {
541            String operation = getOperation();
542            if (operation.equals(INVALID_OP))
543                operation = "";
544
545            String jython = x.getJython() + operation + y.getJython();
546            return jython;
547        }
548    }
549
550    private static abstract class SelectorWrapper {
551        protected static final String BLANK = "-----";
552        private String variable;
553        private final ConstantMap[] color;
554        protected final Selector selector;
555        protected final MultiSpectralDisplay display;
556        protected final MultiSpectralData data;
557        private final JTextField scale = new JTextField(String.format("%3.1f", 1.0));
558        protected WrapperState currentState = WrapperState.DISABLED;
559
560        public SelectorWrapper(final String variable, final ConstantMap[] color, final HydraCombo control, final Console console) {
561            this.display = control.getMultiSpectralDisplay();
562            this.data = control.getMultiSpectralDisplay().getMultiSpectralData();
563            this.variable = variable;
564            this.color = color;
565            this.selector = new Selector(control.init_wavenumber, color, control, console);
566            this.selector.addName(variable);
567        }
568
569        public Selector getSelector() {
570            return selector;
571        }
572
573        public JPanel getPanel() {
574            JPanel panel = new JPanel(new FlowLayout());
575            JComponent comp = getWavenumberComponent();
576            float r = new Double(color[0].getConstant()).floatValue();
577            float g = new Double(color[1].getConstant()).floatValue();
578            float b = new Double(color[2].getConstant()).floatValue();
579            comp.setBorder(new LineBorder(new Color(r, g, b), 2));
580            panel.add(scale);
581            panel.add(comp);
582            return panel;
583        }
584
585        public String getJython() {
586            if (!isValid())
587                return "";
588            return "(" + scale.getText() + "*" + variable + ")";
589        }
590
591        public boolean isValid() {
592            return !getValue().equals(BLANK);
593        }
594
595        public void enable() {
596            setValue(Float.toString(selector.getWaveNumber()));
597            currentState = WrapperState.ENABLED;
598        }
599
600        public void disable() {
601            setValue(BLANK);
602            currentState = WrapperState.DISABLED;
603        }
604
605        public void update() {
606            setValue(Float.toString(selector.getWaveNumber()));
607        }
608
609        public Hashtable<String, String> persistSelectorWrapper() {
610            Hashtable<String, String> table = new Hashtable<String, String>(3);
611            String scaleText = scale.getText();
612            String waveText = getValue();
613
614            if (scaleText == null || scaleText.length() == 0)
615                scaleText = "1.0";
616            if (waveText == null || waveText.length() == 0 || !isValid())
617                waveText = BLANK;
618
619            table.put("variable", variable);
620            table.put("scale", scale.getText());
621            table.put("wave", getValue());
622            return table;
623        }
624
625        public void unpersistSelectorWrapper(final Hashtable<String, String> table) {
626            variable = table.get("variable");
627            selector.addName(variable);
628            scale.setText(String.format("%3.1f", new Float(table.get("scale"))));
629
630            String waveText = table.get("wave");
631            if (waveText.equals(BLANK)) {
632                disable();
633            } else {
634                float wave = new Float(table.get("wave"));
635                selector.setWaveNumber(wave);
636                if (isValid())
637                    update();
638            }
639        }
640
641        public abstract JComponent getWavenumberComponent();
642
643        public abstract void setValue(final String value);
644
645        public abstract String getValue();
646    }
647
648    private static class HyperspectralSelectorWrapper extends SelectorWrapper {
649        private final JTextField wavenumber;
650        public HyperspectralSelectorWrapper(final String variable, final ConstantMap[] color, final HydraCombo control, final Console console) {
651            super(variable, color, control, console);
652            wavenumber = new JTextField(BLANK, 7);
653
654            wavenumber.addActionListener(new ActionListener() {
655                public void actionPerformed(final ActionEvent e) {
656                    String textVal = wavenumber.getText();
657                    if (textVal.equals(BLANK))
658                        return;
659
660                    float wave = Float.parseFloat(textVal.trim());
661                    control.updateComboPanel(getSelector().getId(), wave);
662                }
663            });
664        }
665
666        @Override public JComponent getWavenumberComponent() {
667            return wavenumber;
668        }
669
670        @Override public void setValue(final String value) {
671            if (value == null)
672                throw new NullPointerException("");
673
674            if (!value.equals(BLANK)) {
675                float wave = Float.parseFloat(value);
676                String fmt = String.format("%7.2f", wave);
677                wavenumber.setText(fmt);
678            }
679        }
680
681        public String getValue() {
682            return wavenumber.getText();
683        }
684    }
685
686    private static class MultispectralSelectorWrapper extends SelectorWrapper {
687        private final HydraCombo control;
688        private final JComboBox bands;
689
690        public MultispectralSelectorWrapper(final String variable, final ConstantMap[] color, final HydraCombo control, final Console console) {
691            super(variable, color, control, console);
692            this.control = control;
693            removeMSDListeners();
694            bands = bigBadBox(control);
695        }
696
697        private void removeMSDListeners() {
698            JComboBox box = display.getBandSelectComboBox();
699            for (ActionListener l : box.getActionListeners())
700                box.removeActionListener(l);
701        }
702
703        private JComboBox bigBadBox(final HydraCombo control) {
704            final JComboBox box = new JComboBox();
705            box.addItem(BLANK);
706
707            for (String name : data.getBandNames())
708                box.addItem(name);
709
710            final SelectorWrapper wrapper = this;
711            box.addActionListener(new ActionListener() {
712                public void actionPerformed(final ActionEvent e) {
713                    String selected = (String)box.getSelectedItem();
714                    float wave = Float.NaN;
715
716                    if (!selected.equals(BLANK)) {
717                        Map<String, Float> map = data.getBandNameMap();
718                        if (map.containsKey(selected))
719                            wave = map.get(selected);
720
721                        if (currentState == WrapperState.DISABLED)
722                            control.enableSelectorForWrapper(wrapper);
723                        control.updateComboPanel(getSelector().getId(), wave);
724                    } else {
725                        control.disableSelectorForWrapper(wrapper);
726                    }
727                }
728            });
729            
730            return box;
731        }
732        
733        @Override public JComponent getWavenumberComponent() {
734            return bands;
735        }
736
737        @Override public void setValue(final String value) {
738            if (value == null)
739                throw new NullPointerException();
740
741            if (!value.equals(BLANK)) {
742                String name = data.getBandNameFromWaveNumber(Float.parseFloat(value));
743                bands.setSelectedItem(name);
744            } else {     
745                bands.setSelectedItem(BLANK);
746            }
747        }
748
749        @Override public String getValue() {
750            return (String)bands.getSelectedItem();
751        }
752    }
753}